diff --git a/pep-0543.rst b/pep-0543.rst index 539863ac7f3..99ed2605e0f 100644 --- a/pep-0543.rst +++ b/pep-0543.rst @@ -9,7 +9,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 17-Oct-2016 Python-Version: 3.7 -Post-History: 11-Jan-2017, 19-Jan-2017, 02-Feb-2017, 09-Feb-2017 +Post-History: 11-Jan-2017, 19-Jan-2017, 02-Feb-2017, 09-Feb-2017, 29-Dec-2017 Abstract @@ -1256,6 +1256,32 @@ The definitions of the errors are below:: attack and so can ignore this exception. """ +File format +~~~~~~~~~~~ + +Certificates and private keys can be encoded in multiple ways. The most +important file formats are DER and PEM. DER (*Distinguished Encoding +Rules*) describes ASN.1 data structure as bytes. The PEM format is +base64-encoded DER with a header, footer, and optional metadata. For +example a PEM-encoded encrypted private key in PKCS#8 format has additional +PKCS#5 metadata. A file in DER format can only contain one certificate or +key, while a PEM encoded file can contain multiple certs and a key together +with additional text. + +A PKCS#12 file is an archive format private keys, certificates, trust +anchors and other data with optional encryption and signature. The PKCS#12 +format is out of scope. + +:: + + class FileFormat(Enum): + DER = auto() + PEM = auto() + +Libraries may define their own file formats, too. For example OpenSSL has +trusted certificates, which are regular PEM-encoded certificates with an AUX +section appended. + Certificates ~~~~~~~~~~~~ @@ -1283,19 +1309,28 @@ an individual concrete implementation are also hashable. class Certificate(metaclass=ABCMeta): @abstractclassmethod - def from_buffer(cls, buffer: bytes): + def from_buffer( + cls, + buffer: bytes, + *, + password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None, + format: FileFormat = FileFormat.PEM + ) -> Certificate: """ Creates a Certificate object from a byte buffer. This byte buffer - may be either PEM-encoded or DER-encoded. If the buffer is PEM - encoded it *must* begin with the standard PEM preamble (a series of - dashes followed by the ASCII bytes "BEGIN CERTIFICATE" and another - series of dashes). In the absence of that preamble, the - implementation may assume that the certificate is DER-encoded - instead. + may be either PEM-encoded or DER-encoded. The password argument + may be used in the future for additional file formats like + PKCS#12 files. """ @abstractclassmethod - def from_file(cls, path: Union[pathlib.Path, AnyStr]): + def from_file( + cls, + path: Union[pathlib.Path, AnyStr], + *, + password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None, + format: FileFormat = FileFormat.PEM + ) -> Certificate: """ Creates a Certificate object from a file on disk. This method may be a convenience method that wraps ``open`` and ``from_buffer``, @@ -1304,6 +1339,75 @@ an individual concrete implementation are also hashable. code. """ + @abstractclassmethod + def chain_from_buffer( + cls, + buffer: bytes, + *, + password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None, + format: FileFormat = FileFormat.PEM + ) -> Tuple[Certificate]: + """ + Creates a Certificate object from a byte buffer. This byte buffer + must be PEM-encoded. The password and format arguments are + currently not used. + """ + + @abstractclassmethod + def chain_from_file( + cls, + path: Union[pathlib.Path, AnyStr], + *, + password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None, + format: FileFormat = FileFormat.PEM + ) -> Tuple[Certificate]: + """ + Creates a Certificate chain from a file on disk. This method may + be a convenience method that wraps ``open`` and + ``chain_from_buffer``, but some TLS implementations may be able + to provide more-secure or faster methods of loading certificates + that do not involve Python code. + + A certificate chain must start with the end-entity cert (server + or client cert) and may be followed by one or more intermediate + CA certs. The second cert must be the issuer of the first cert, + the third cert the issuer of the second cert, and so on. The + chain must not contain a trust anchor (root cert). + """ + + @abstractclassmethod + def bundle_from_buffer( + cls, + buffer: bytes, + *, + password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None, + format: FileFormat = FileFormat.PEM + ) -> List[Certificate]: + """ + Creates a bundle of Certificate objects from a byte buffer. This + byte buffer must be PEM-encoded. The password and format + arguments are currently not used. + """ + + @abstractclassmethod + def bundle_from_file( + cls, + path: Union[pathlib.Path, AnyStr], + *, + password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None, + format: FileFormat = FileFormat.PEM + ) -> List[Certificate]: + """ + Creates a Certificate bundle from a file on disk. This method may + be a convenience method that wraps ``open`` and + ``bundle_from_buffer``, but some TLS implementations may be able + to provide more-secure or faster methods of loading certificates + that do not involve Python code. + """ + + def dump(self, format: FileFormat = FileFormat.PEM) -> bytes: + """Dump certificate as PEM or DER-encoded bytes. + """ Private Keys ~~~~~~~~~~~~ @@ -1318,17 +1422,16 @@ This class has all the caveats of the ``Certificate`` class. class PrivateKey(metaclass=ABCMeta): @abstractclassmethod - def from_buffer(cls, - buffer: bytes, - password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None): + def from_buffer( + cls, + buffer: bytes, + *, + password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None, + format: FileFormat = FileFormat.PEM + ) -> PrivateKey: """ Creates a PrivateKey object from a byte buffer. This byte buffer - may be either PEM-encoded or DER-encoded. If the buffer is PEM - encoded it *must* begin with the standard PEM preamble (a series of - dashes followed by the ASCII bytes "BEGIN", the key type, and - another series of dashes). In the absence of that preamble, the - implementation may assume that the certificate is DER-encoded - instead. + may be either PEM-encoded or DER-encoded. The key may additionally be encrypted. If it is, the ``password`` argument can be used to decrypt the key. The ``password`` argument @@ -1342,9 +1445,13 @@ This class has all the caveats of the ``Certificate`` class. """ @abstractclassmethod - def from_file(cls, - path: Union[pathlib.Path, bytes, str], - password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None): + def from_file( + cls, + path: Union[pathlib.Path, bytes, str], + *, + password: Optional[Union[Callable[[], Union[bytes, bytearray]], bytes, bytearray]] = None, + format: FileFormat = FileFormat.PEM + ) -> PrivateKey: """ Creates a PrivateKey object from a file on disk. This method may be a convenience method that wraps ``open`` and ``from_buffer``,