Finish documenting <openssl/pem.h>

Fixed: 42290574
Change-Id: I4addc0e0b59199e55c9b08eb16c880ff65009c9a
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/97487
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/pem/pem_pkey.cc b/crypto/pem/pem_pkey.cc
index 58eb720..836c4a9 100644
--- a/crypto/pem/pem_pkey.cc
+++ b/crypto/pem/pem_pkey.cc
@@ -67,7 +67,7 @@
     if (!cb) {
       cb = PEM_def_callback;
     }
-    pass_len = cb(psbuf, PEM_BUFSIZE, 0, u);
+    pass_len = cb(psbuf, PEM_BUFSIZE, /*enc=*/0, u);
     if (pass_len < 0) {
       OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ);
       X509_SIG_free(p8);
@@ -82,7 +82,7 @@
     ret = EVP_PKCS82PKEY(p8inf);
     if (x) {
       if (*x) {
-        EVP_PKEY_free((EVP_PKEY *)*x);
+        EVP_PKEY_free(*x);
       }
       *x = ret;
     }
diff --git a/include/openssl/pem.h b/include/openssl/pem.h
index 6cd1b05..cd36899 100644
--- a/include/openssl/pem.h
+++ b/include/openssl/pem.h
@@ -127,19 +127,19 @@
 #endif  // Sample functions
 
 
-// Reading and writing objects as PEM.
+// Reading and writing X.509 structures as PEM.
 
-// PEM_read_bio_X509 reads a PEM block of type "CERTIFICATE" or "X509
+// PEM_read_bio_X509 reads a PEM block of type "CERTIFICATE" (RFC 7468) or "X509
 // CERTIFICATE", as described in `PEM_read_bio_SAMPLE`.
 OPENSSL_EXPORT X509 *PEM_read_bio_X509(BIO *bio, X509 **out,
                                        pem_password_cb *cb, void *userdata);
 
-// PEM_write_bio_X509 writes a PEM block of type "CERTIFICATE", as described in
-// `PEM_write_bio_SAMPLE`.
+// PEM_write_bio_X509 writes a PEM block of type "CERTIFICATE" (RFC 7468), as
+// described in `PEM_write_bio_SAMPLE`.
 OPENSSL_EXPORT int PEM_write_bio_X509(BIO *bio, const X509 *in);
 
-// PEM_read_bio_X509_AUX reads a PEM block of type "CERTIFICATE", "X509
-// CERTIFICATE", or "TRUSTED CERTIFICATE", as described in
+// PEM_read_bio_X509_AUX reads a PEM block of type "CERTIFICATE" (RFC 7468),
+// "X509 CERTIFICATE", or "TRUSTED CERTIFICATE", as described in
 // `PEM_read_bio_SAMPLE`.
 //
 // WARNING: This function parses auxiliary properties as in `d2i_X509_AUX`.
@@ -155,17 +155,46 @@
 // auxiliary properties. See `i2d_X509_AUX`.
 OPENSSL_EXPORT int PEM_write_bio_X509_AUX(BIO *bio, const X509 *in);
 
-// PEM_write_bio_X509_CRL writes a PEM block of type "X509 CRL", as described in
-// `PEM_write_bio_SAMPLE`.
-OPENSSL_EXPORT int PEM_write_bio_X509_CRL(BIO *bio, const X509_CRL *in);
-
-// PEM_read_bio_X509_CRL reads a PEM block of type "X509 CRL", as described in
-// `PEM_read_bio_SAMPLE`.
+// PEM_read_bio_X509_CRL reads a PEM block of type "X509 CRL" (RFC 7468), as
+// described in `PEM_read_bio_SAMPLE`.
 OPENSSL_EXPORT X509_CRL *PEM_read_bio_X509_CRL(BIO *bio, X509_CRL **out,
                                                pem_password_cb *cb,
                                                void *userdata);
 
-// PEM_X509_INFO_read_bio reads PEM blocks from `bp` and decodes any
+// PEM_write_bio_X509_CRL writes a PEM block of type "X509 CRL" (RFC 7468), as
+// described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_X509_CRL(BIO *bio, const X509_CRL *in);
+
+// PEM_read_bio_X509_REQ reads a PEM block of type "CERTIFICATE REQUEST"
+// (RFC 7468) or "NEW CERTIFICATE REQUEST", as described in
+// `PEM_read_bio_SAMPLE`.
+OPENSSL_EXPORT X509_REQ *PEM_read_bio_X509_REQ(BIO *bio, X509_REQ **out,
+                                               pem_password_cb *cb,
+                                               void *userdata);
+
+// PEM_write_bio_X509_REQ writes a PEM block of type "CERTIFICATE REQUEST"
+// (RFC 7468), as described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_X509_REQ(BIO *bio, const X509_REQ *in);
+
+// PEM_write_bio_X509_REQ_NEW writes a PEM block of type "NEW CERTIFICATE
+// REQUEST", as described in `PEM_write_bio_SAMPLE`. Prefer to use
+// `PEM_write_bio_X509_REQ`. "NEW CERTIFICATE REQUEST" is the older type.
+OPENSSL_EXPORT int PEM_write_bio_X509_REQ_NEW(BIO *bio, const X509_REQ *in);
+
+// PEM_read_bio_PKCS7 reads a PEM block of type "PKCS7" (RFC 7468) or "PKCS #7
+// SIGNED DATA", as described in `PEM_read_bio_SAMPLE`.
+//
+// This function also accepts type "CERTIFICATE" but decodes the contents as a
+// PKCS #7 structure rather than a certificate. This is a historical workaround
+// for an old CA bug.
+OPENSSL_EXPORT PKCS7 *PEM_read_bio_PKCS7(BIO *bio, PKCS7 **out,
+                                         pem_password_cb *cb, void *userdata);
+
+// PEM_write_bio_PKCS7 writes a PEM block of type "PKCS7" (RFC 7468), as
+// described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_PKCS7(BIO *bio, const PKCS7 *in);
+
+// PEM_X509_INFO_read_bio reads PEM blocks from `bio` and decodes any
 // certificates, CRLs, and private keys found. It returns a
 // `STACK_OF(X509_INFO)` structure containing the results, or NULL on error.
 //
@@ -177,7 +206,7 @@
 // on success. In this case, the caller retains ownership of `sk` in both
 // success and failure.
 //
-// This function will decrypt any encrypted certificates in `bp`, using `cb`,
+// This function will decrypt any encrypted certificates in `bio`, using `cb`,
 // but it will not decrypt encrypted private keys. Encrypted private keys are
 // instead represented as placeholder `X509_INFO` objects with an empty `x_pkey`
 // field. This allows this function to be used with inputs with unencrypted
@@ -190,10 +219,229 @@
 // input to this function allows an attacker to influence those properties. See
 // `d2i_X509_AUX` for details.
 OPENSSL_EXPORT STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(
-    BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *userdata);
+    BIO *bio, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *userdata);
 
-// The following functions behave like corresponding `PEM_read_bio_*` function,
-// but read from `fp`.
+
+// Reading and writing keys as PEM.
+//
+// There are multiple PEM formats for public and private keys:
+//
+// Public keys are generally encoded with type "PUBLIC KEY" (RFC 7468), which
+// encodes a SubjectPublicKeyInfo structure (RFC 5280).
+//
+// Private keys may be encoded with type "PRIVATE KEY" or "ENCRYPTED PRIVATE
+// KEY" (RFC 7468), which encode a PrivateKeyInfo or EncryptedPrivateKeyInfo
+// (RFC 5208) structure. EncryptedPrivateKeyInfo is, itself, a mechanism for
+// encrypting private keys with a password, so private keys may be encrypted
+// with PEM encryption, PKCS #8 encryption, or both.
+//
+// There are also older algorithm-specific PEM types for public and private
+// keys, including "RSA PUBLIC KEY", "RSA PRIVATE KEY", "EC PRIVATE KEY", and
+// "DSA PRIVATE KEY". Some functions in this library will read or write them.
+//
+// If unsure, use the "PUBLIC KEY" and "PRIVATE KEY" formats.
+
+// PEM_read_bio_PrivateKey reads a PEM block containing a private key, as
+// described in `PEM_read_bio_SAMPLE`. It handles generic PKCS #8 blocks of type
+// "PRIVATE KEY" and "ENCRYPTED PRIVATE KEY", as well as key-specific formats
+// like "RSA PRIVATE KEY", "EC PRIVATE KEY", and "DSA PRIVATE KEY".
+//
+// `cb` and `userdata` are used to look up the password for both PEM-level
+// encryption as well as PKCS #8 encryption, in the case of "ENCRYPTED PRIVATE
+// KEY" blocks.
+OPENSSL_EXPORT EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bio, EVP_PKEY **out,
+                                                 pem_password_cb *cb,
+                                                 void *userdata);
+
+// PEM_write_bio_PrivateKey writes `in` to `bio` in PKCS#8 format, as described
+// in `PEM_write_bio_SAMPLE`. However, it interprets encryption parameters
+// differently:
+//
+// - If not encrypting (`enc` is NULL), it writes the key as a PEM block of type
+//   "PRIVATE KEY".
+//
+// - If encrypted (`enc` is not NULL), it encrypts the key in an
+//   EncryptedPrivateKeyInfo using PBES2 (see `PKCS8_encrypt`) and writes the
+//   result as a PEM block of type "ENCRYPTED PRIVATE KEY".
+OPENSSL_EXPORT int PEM_write_bio_PrivateKey(BIO *bio, const EVP_PKEY *in,
+                                            const EVP_CIPHER *enc,
+                                            const uint8_t *pass, int pass_len,
+                                            pem_password_cb *cb,
+                                            void *userdata);
+
+// PEM_read_bio_PUBKEY reads a PEM block of type "PUBLIC KEY", as described in
+// `PEM_read_bio_SAMPLE`.
+OPENSSL_EXPORT EVP_PKEY *PEM_read_bio_PUBKEY(BIO *bio, EVP_PKEY **out,
+                                             pem_password_cb *cb,
+                                             void *userdata);
+
+// PEM_write_bio_PUBKEY writes `in` as a PEM block of type "PUBLIC KEY", as
+// described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_PUBKEY(BIO *bio, const EVP_PKEY *in);
+
+// PEM_write_bio_PKCS8PrivateKey_nid behaves like `PEM_write_bio_PrivateKey`
+// but uses the PBES1 algorithm specified by `nid` for encryption. See also
+// `PKCS8_encrypt`. If `nid` is -1, it writes the private key unencrypted.
+OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey_nid(
+    BIO *bio, const EVP_PKEY *in, int nid, const char *pass, int pass_len,
+    pem_password_cb *cb, void *userdata);
+
+// PEM_write_bio_PKCS8PrivateKey is an alias for `PEM_write_bio_PrivateKey`.
+OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey(BIO *bio, const EVP_PKEY *in,
+                                                 const EVP_CIPHER *enc,
+                                                 const char *pass, int pass_len,
+                                                 pem_password_cb *cb,
+                                                 void *userdata);
+
+// PEM_write_PKCS8PrivateKey_nid behaves like
+// `PEM_write_bio_PKCS8PrivateKey_nid` but writes to `fp`.
+OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey_nid(FILE *fp, const EVP_PKEY *in,
+                                                 int nid, const char *pass,
+                                                 int pass_len,
+                                                 pem_password_cb *cb,
+                                                 void *userdata);
+
+// PEM_write_PKCS8PrivateKey behaves like `PEM_write_bio_PKCS8PrivateKey` but
+// writes to `fp`.
+OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey(FILE *fp, const EVP_PKEY *in,
+                                             const EVP_CIPHER *enc,
+                                             const char *pass, int pass_len,
+                                             pem_password_cb *cb,
+                                             void *userdata);
+
+// PEM_read_bio_PKCS8 reads a PEM block of type "ENCRYPTED PRIVATE KEY", as
+// described in `PEM_read_bio_SAMPLE`.
+//
+// Although this function accepts `cb` and `userdata` to decrypt the PEM-level
+// encryption, it does not decrypt the EncryptedPrivateKeyInfo structure. It
+// returns the encrypted key as an `X509_SIG` object which, despite its name, is
+// an algorithm and octet string pair.
+OPENSSL_EXPORT X509_SIG *PEM_read_bio_PKCS8(BIO *bio, X509_SIG **out,
+                                            pem_password_cb *cb,
+                                            void *userdata);
+
+// PEM_write_bio_PKCS8 writes a PEM block of type "ENCRYPTED PRIVATE KEY", as
+// described in `PEM_write_bio_SAMPLE`. `in` is used to represent an
+// already-encrypted EncryptedPrivateKeyInfo structure.
+OPENSSL_EXPORT int PEM_write_bio_PKCS8(BIO *bio, const X509_SIG *in);
+
+// PEM_read_bio_PKCS8_PRIV_KEY_INFO reads a PEM block of type "PRIVATE KEY", as
+// described in `PEM_read_bio_SAMPLE`.
+OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PEM_read_bio_PKCS8_PRIV_KEY_INFO(
+    BIO *bio, PKCS8_PRIV_KEY_INFO **out, pem_password_cb *cb, void *userdata);
+
+// PEM_write_bio_PKCS8_PRIV_KEY_INFO writes a PEM block of type "PRIVATE KEY",
+// as described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_PKCS8_PRIV_KEY_INFO(
+    BIO *bio, const PKCS8_PRIV_KEY_INFO *in);
+
+// PEM_read_bio_RSAPrivateKey behaves like `PEM_read_bio_PrivateKey` but only
+// returns RSA keys, represented as an `RSA` object. Keys of other types result
+// in an error.
+OPENSSL_EXPORT RSA *PEM_read_bio_RSAPrivateKey(BIO *bio, RSA **out,
+                                               pem_password_cb *cb,
+                                               void *userdata);
+
+// PEM_write_bio_RSAPrivateKey writes `in` as a PEM block of type "RSA PRIVATE
+// KEY", as described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_RSAPrivateKey(
+    BIO *bio, const RSA *in, const EVP_CIPHER *enc, const uint8_t *pass,
+    int pass_len, pem_password_cb *cb, void *userdata);
+
+// PEM_read_bio_RSAPublicKey reads a PEM block of type "RSA PUBLIC KEY", as
+// described in `PEM_read_bio_SAMPLE`.
+OPENSSL_EXPORT RSA *PEM_read_bio_RSAPublicKey(BIO *bio, RSA **out,
+                                              pem_password_cb *cb,
+                                              void *userdata);
+
+// PEM_write_bio_RSAPublicKey writes a PEM block of type "RSA PUBLIC KEY", as
+// described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_RSAPublicKey(BIO *bio, const RSA *in);
+
+// PEM_read_bio_RSA_PUBKEY behaves like `PEM_read_bio_PUBKEY` but only returns
+// RSA keys, represented as an `RSA` object. Keys of other types result in an
+// error.
+OPENSSL_EXPORT RSA *PEM_read_bio_RSA_PUBKEY(BIO *bio, RSA **out,
+                                            pem_password_cb *cb,
+                                            void *userdata);
+
+// PEM_write_bio_RSA_PUBKEY writes `in` as a PEM block of type "PUBLIC KEY", as
+// described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_RSA_PUBKEY(BIO *bio, const RSA *in);
+
+// PEM_read_bio_DSAPrivateKey behaves like `PEM_read_bio_PrivateKey` but only
+// returns DSA keys, represented as a `DSA` object. Keys of other types result
+// in an error.
+OPENSSL_EXPORT DSA *PEM_read_bio_DSAPrivateKey(BIO *bio, DSA **out,
+                                               pem_password_cb *cb,
+                                               void *userdata);
+
+// PEM_write_bio_DSAPrivateKey writes `in` as a PEM block of type "DSA PRIVATE
+// KEY", as described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_DSAPrivateKey(
+    BIO *bio, const DSA *in, const EVP_CIPHER *enc, const uint8_t *pass,
+    int pass_len, pem_password_cb *cb, void *userdata);
+
+// PEM_read_bio_DSA_PUBKEY behaves like `PEM_read_bio_PUBKEY` but only returns
+// DSA keys, represented as a `DSA` object. Keys of other types result in an
+// error.
+OPENSSL_EXPORT DSA *PEM_read_bio_DSA_PUBKEY(BIO *bio, DSA **out,
+                                            pem_password_cb *cb,
+                                            void *userdata);
+
+// PEM_write_bio_DSA_PUBKEY writes `in` in SubjectPublicKeyInfo format as a PEM
+// block of type "PUBLIC KEY", as described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_DSA_PUBKEY(BIO *bio, const DSA *in);
+
+// PEM_read_bio_DSAparams reads a PEM block of type "DSA PARAMETERS", as
+// described in `PEM_read_bio_SAMPLE`.
+OPENSSL_EXPORT DSA *PEM_read_bio_DSAparams(BIO *bio, DSA **out,
+                                           pem_password_cb *cb, void *userdata);
+
+// PEM_write_bio_DSAparams writes a PEM block of type "DSA PARAMETERS", as
+// described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_DSAparams(BIO *bio, const DSA *in);
+
+// PEM_read_bio_ECPrivateKey behaves like `PEM_read_bio_PrivateKey` but only
+// returns EC keys, represented as an `EC_KEY` object. Keys of other types
+// result in an error.
+OPENSSL_EXPORT EC_KEY *PEM_read_bio_ECPrivateKey(BIO *bio, EC_KEY **out,
+                                                 pem_password_cb *cb,
+                                                 void *userdata);
+
+// PEM_write_bio_ECPrivateKey writes `in` as a PEM block of type "EC PRIVATE
+// KEY", as described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_ECPrivateKey(BIO *bio, const EC_KEY *in,
+                                              const EVP_CIPHER *enc,
+                                              const uint8_t *pass, int pass_len,
+                                              pem_password_cb *cb,
+                                              void *userdata);
+
+// PEM_read_bio_EC_PUBKEY behaves like `PEM_read_bio_PUBKEY` but only returns
+// EC keys, represented as an `EC_KEY` object. Keys of other types result in an
+// error.
+OPENSSL_EXPORT EC_KEY *PEM_read_bio_EC_PUBKEY(BIO *bio, EC_KEY **out,
+                                              pem_password_cb *cb,
+                                              void *userdata);
+
+// PEM_write_bio_EC_PUBKEY writes `in` in SubjectPublicKeyInfo format as a PEM
+// block of type "PUBLIC KEY", as described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_EC_PUBKEY(BIO *bio, const EC_KEY *in);
+
+// PEM_read_bio_DHparams reads a PEM block of type "DH PARAMETERS", as described
+// in `PEM_read_bio_SAMPLE`.
+OPENSSL_EXPORT DH *PEM_read_bio_DHparams(BIO *bio, DH **out,
+                                         pem_password_cb *cb, void *userdata);
+
+// PEM_write_bio_DHparams writes a PEM block of type "DH PARAMETERS", as
+// described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_DHparams(BIO *bio, const DH *in);
+
+
+// File-based functions.
+
+// The following functions behave like the corresponding `PEM_read_bio_*`
+// functions, but read from `fp`.
 OPENSSL_EXPORT X509 *PEM_read_X509(FILE *fp, X509 **out, pem_password_cb *cb,
                                    void *userdata);
 OPENSSL_EXPORT X509_CRL *PEM_read_X509_CRL(FILE *fp, X509_CRL **out,
@@ -204,12 +452,73 @@
                                                        STACK_OF(X509_INFO) *sk,
                                                        pem_password_cb *cb,
                                                        void *userdata);
+OPENSSL_EXPORT X509_REQ *PEM_read_X509_REQ(FILE *fp, X509_REQ **out,
+                                           pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT PKCS7 *PEM_read_PKCS7(FILE *fp, PKCS7 **out, pem_password_cb *cb,
+                                     void *userdata);
+OPENSSL_EXPORT X509_SIG *PEM_read_PKCS8(FILE *fp, X509_SIG **out,
+                                        pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PEM_read_PKCS8_PRIV_KEY_INFO(
+    FILE *fp, PKCS8_PRIV_KEY_INFO **out, pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **out,
+                                           pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT RSA *PEM_read_RSAPublicKey(FILE *fp, RSA **out,
+                                          pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT RSA *PEM_read_RSA_PUBKEY(FILE *fp, RSA **out,
+                                        pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT DSA *PEM_read_DSAPrivateKey(FILE *fp, DSA **out,
+                                           pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT DSA *PEM_read_DSA_PUBKEY(FILE *fp, DSA **out,
+                                        pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT DSA *PEM_read_DSAparams(FILE *fp, DSA **out, pem_password_cb *cb,
+                                       void *userdata);
+OPENSSL_EXPORT EC_KEY *PEM_read_ECPrivateKey(FILE *fp, EC_KEY **out,
+                                             pem_password_cb *cb,
+                                             void *userdata);
+OPENSSL_EXPORT EC_KEY *PEM_read_EC_PUBKEY(FILE *fp, EC_KEY **out,
+                                          pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT DH *PEM_read_DHparams(FILE *fp, DH **out, pem_password_cb *cb,
+                                     void *userdata);
+OPENSSL_EXPORT EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **out,
+                                             pem_password_cb *cb,
+                                             void *userdata);
+OPENSSL_EXPORT EVP_PKEY *PEM_read_PUBKEY(FILE *fp, EVP_PKEY **out,
+                                         pem_password_cb *cb, void *userdata);
 
-// The following functions behave like corresponding `PEM_write_bio_*` function,
-// but write to `fp`.
+// The following functions behave like the corresponding `PEM_write_bio_*`
+// functions, but write to `fp`.
 OPENSSL_EXPORT int PEM_write_X509(FILE *fp, const X509 *x);
 OPENSSL_EXPORT int PEM_write_X509_CRL(FILE *fp, const X509_CRL *in);
 OPENSSL_EXPORT int PEM_write_X509_AUX(FILE *fp, const X509 *in);
+OPENSSL_EXPORT int PEM_write_X509_REQ(FILE *fp, const X509_REQ *in);
+OPENSSL_EXPORT int PEM_write_X509_REQ_NEW(FILE *fp, const X509_REQ *in);
+OPENSSL_EXPORT int PEM_write_PKCS7(FILE *fp, const PKCS7 *in);
+OPENSSL_EXPORT int PEM_write_PKCS8(FILE *fp, const X509_SIG *in);
+OPENSSL_EXPORT int PEM_write_PKCS8_PRIV_KEY_INFO(FILE *fp,
+                                                 const PKCS8_PRIV_KEY_INFO *in);
+OPENSSL_EXPORT int PEM_write_RSAPrivateKey(FILE *fp, const RSA *in,
+                                           const EVP_CIPHER *enc,
+                                           const uint8_t *pass, int pass_len,
+                                           pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT int PEM_write_RSAPublicKey(FILE *fp, const RSA *in);
+OPENSSL_EXPORT int PEM_write_RSA_PUBKEY(FILE *fp, const RSA *in);
+OPENSSL_EXPORT int PEM_write_DSAPrivateKey(FILE *fp, const DSA *in,
+                                           const EVP_CIPHER *enc,
+                                           const uint8_t *pass, int pass_len,
+                                           pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT int PEM_write_DSA_PUBKEY(FILE *fp, const DSA *in);
+OPENSSL_EXPORT int PEM_write_DSAparams(FILE *fp, const DSA *in);
+OPENSSL_EXPORT int PEM_write_ECPrivateKey(FILE *fp, const EC_KEY *in,
+                                          const EVP_CIPHER *enc,
+                                          const uint8_t *pass, int pass_len,
+                                          pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT int PEM_write_EC_PUBKEY(FILE *fp, const EC_KEY *in);
+OPENSSL_EXPORT int PEM_write_DHparams(FILE *fp, const DH *in);
+OPENSSL_EXPORT int PEM_write_PrivateKey(FILE *fp, const EVP_PKEY *in,
+                                        const EVP_CIPHER *enc,
+                                        const uint8_t *pass, int pass_len,
+                                        pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT int PEM_write_PUBKEY(FILE *fp, const EVP_PKEY *in);
 
 
 // Reading and writing raw PEM blocks.
@@ -333,6 +642,76 @@
                                       pem_password_cb *cb, void *userdata);
 
 
+// Reading and writing DER-encoded private keys.
+
+// d2i_PKCS8PrivateKey_bio reads a DER-encoded EncryptedPrivateKey structure
+// (RFC 5208) from `bio`, decrypts it with `PKCS8_decrypt`, and returns the
+// result as a newly-allocated `EVP_PKEY`, or NULL on error. On success, if
+// `out` is non-NULL, it additionally frees the previous value at `*out` and
+// updates `*out` to the result. The password is determined by calling `cb`, or
+// `PEM_def_callback` if NULL.
+OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bio, EVP_PKEY **out,
+                                                 pem_password_cb *cb,
+                                                 void *userdata);
+
+// i2d_PKCS8PrivateKey_bio encodes `in` as a DER-encoded structure and writes
+// it to `bio`. It returns one on success and zero on error. The structure used
+// depends on `enc`:
+//
+// - If `enc` is NULL, it writes a PrivateKeyInfo structure (RFC 5208).
+//
+// - If `enc` is non-NULL, it writes an EncryptedPrivateKeyInfo structure (RFC
+//   5280). The key is encrypted with PBES2, as in `PKCS8_encrypt`. The password
+//   is specified by `pass`, `cb`, and `userdata`, as in `PEM_write_bio_SAMPLE`.
+//
+// WARNING: PrivateKeyInfo and EncryptedPrivateKeyInfo are different formats,
+// and DER does not include a type header. The encrypted and unencrypted modes
+// of this function should not be mixed in the same context.
+OPENSSL_EXPORT int i2d_PKCS8PrivateKey_bio(BIO *bio, const EVP_PKEY *in,
+                                           const EVP_CIPHER *enc,
+                                           const char *pass, int pass_len,
+                                           pem_password_cb *cb, void *userdata);
+
+// i2d_PKCS8PrivateKey_nid_bio encodes `in` as a DER-encoded structure and
+// writes it to `bio`. It returns one on success and zero on error. The
+// structure used depends on `nid`:
+//
+// - If `nid` is -1, it writes a PrivateKeyInfo structure (RFC 5208).
+//
+// - Otherwise, it writes an EncryptedPrivateKeyInfo structure (RFC 5280). The
+//   key is encrypted with PBES1, as in `PKCS8_encrypt`. The password is
+//   specified by `pass`, `cb`, and `userdata`, as in `PEM_write_bio_SAMPLE`.
+//
+// WARNING: PrivateKeyInfo and EncryptedPrivateKeyInfo are different formats,
+// and DER does not include a type header. The encrypted and unencrypted modes
+// of this function should not be mixed in the same context.
+OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_bio(BIO *bio, const EVP_PKEY *in,
+                                               int nid, const char *pass,
+                                               int pass_len,
+                                               pem_password_cb *cb,
+                                               void *userdata);
+
+// i2d_PKCS8PrivateKey_fp behaves like `i2d_PKCS8PrivateKey_bio` but writes to
+// `fp`.
+OPENSSL_EXPORT int i2d_PKCS8PrivateKey_fp(FILE *fp, const EVP_PKEY *in,
+                                          const EVP_CIPHER *enc,
+                                          const char *pass, int pass_len,
+                                          pem_password_cb *cb, void *userdata);
+
+// i2d_PKCS8PrivateKey_nid_fp behaves like `i2d_PKCS8PrivateKey_nid_bio` but
+// writes to `fp`.
+OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, const EVP_PKEY *in,
+                                              int nid, const char *pass,
+                                              int pass_len, pem_password_cb *cb,
+                                              void *userdata);
+
+// d2i_PKCS8PrivateKey_fp behaves like `d2i_PKCS8PrivateKey_bio` but reads from
+// `fp`.
+OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **out,
+                                                pem_password_cb *cb,
+                                                void *userdata);
+
+
 // Internal functions.
 //
 // The following functions are used to implement `PEM_read_bio_*` and
@@ -365,130 +744,6 @@
                                   pem_password_cb *callback, void *userdata);
 
 
-// Not yet documented functions.
-//
-// TODO(crbug.com/42290574): Finish documenting and organizing this header.
-
-#define DECLARE_PEM_read_fp(name, type)                      \
-  OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **out, \
-                                       pem_password_cb *cb, void *userdata);
-
-#define DECLARE_PEM_write_fp(name, type) \
-  OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *in);
-
-#define DECLARE_PEM_write_cb_fp(name, type)                                    \
-  OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *in,                \
-                                      const EVP_CIPHER *enc,                   \
-                                      const unsigned char *pass, int pass_len, \
-                                      pem_password_cb *cb, void *userdata);
-
-#define DECLARE_PEM_read_bio(name, type)    \
-  OPENSSL_EXPORT type *PEM_read_bio_##name( \
-      BIO *bio, type **out, pem_password_cb *cb, void *userdata);
-
-#define DECLARE_PEM_write_bio(name, type) \
-  OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bio, const type *in);
-
-#define DECLARE_PEM_write_cb_bio(name, type)                        \
-  OPENSSL_EXPORT int PEM_write_bio_##name(                          \
-      BIO *bio, const type *in, const EVP_CIPHER *enc,              \
-      const unsigned char *pass, int pass_len, pem_password_cb *cb, \
-      void *userdata);
-
-#define DECLARE_PEM_write(name, type) \
-  DECLARE_PEM_write_bio(name, type)   \
-  DECLARE_PEM_write_fp(name, type)
-
-#define DECLARE_PEM_write_cb(name, type) \
-  DECLARE_PEM_write_cb_bio(name, type)   \
-  DECLARE_PEM_write_cb_fp(name, type)
-
-#define DECLARE_PEM_read(name, type) \
-  DECLARE_PEM_read_bio(name, type)   \
-  DECLARE_PEM_read_fp(name, type)
-
-#define DECLARE_PEM_rw(name, type) \
-  DECLARE_PEM_read(name, type)     \
-  DECLARE_PEM_write(name, type)
-
-#define DECLARE_PEM_rw_cb(name, type) \
-  DECLARE_PEM_read(name, type)        \
-  DECLARE_PEM_write_cb(name, type)
-
-
-DECLARE_PEM_rw(X509_REQ, X509_REQ)
-DECLARE_PEM_write(X509_REQ_NEW, X509_REQ)
-
-
-DECLARE_PEM_rw(PKCS7, PKCS7)
-DECLARE_PEM_rw(PKCS8, X509_SIG)
-
-DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
-
-DECLARE_PEM_rw_cb(RSAPrivateKey, RSA)
-
-DECLARE_PEM_rw(RSAPublicKey, RSA)
-DECLARE_PEM_rw(RSA_PUBKEY, RSA)
-
-DECLARE_PEM_rw_cb(DSAPrivateKey, DSA)
-
-DECLARE_PEM_rw(DSA_PUBKEY, DSA)
-
-DECLARE_PEM_rw(DSAparams, DSA)
-
-DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY)
-DECLARE_PEM_rw(EC_PUBKEY, EC_KEY)
-
-
-DECLARE_PEM_rw(DHparams, DH)
-
-
-DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY)
-
-DECLARE_PEM_rw(PUBKEY, EVP_PKEY)
-
-OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, const EVP_PKEY *x,
-                                                     int nid, const char *pass,
-                                                     int pass_len,
-                                                     pem_password_cb *cb,
-                                                     void *u);
-OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey(BIO *bp, const EVP_PKEY *x,
-                                                 const EVP_CIPHER *enc,
-                                                 const char *pass, int pass_len,
-                                                 pem_password_cb *cb, void *u);
-OPENSSL_EXPORT int i2d_PKCS8PrivateKey_bio(BIO *bp, const EVP_PKEY *x,
-                                           const EVP_CIPHER *enc,
-                                           const char *pass, int pass_len,
-                                           pem_password_cb *cb, void *u);
-OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, const EVP_PKEY *x,
-                                               int nid, const char *pass,
-                                               int pass_len,
-                                               pem_password_cb *cb, void *u);
-OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x,
-                                                 pem_password_cb *cb, void *u);
-
-OPENSSL_EXPORT int i2d_PKCS8PrivateKey_fp(FILE *fp, const EVP_PKEY *x,
-                                          const EVP_CIPHER *enc,
-                                          const char *pass, int pass_len,
-                                          pem_password_cb *cb, void *u);
-OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, const EVP_PKEY *x,
-                                              int nid, const char *pass,
-                                              int pass_len, pem_password_cb *cb,
-                                              void *u);
-OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey_nid(FILE *fp, const EVP_PKEY *x,
-                                                 int nid, const char *pass,
-                                                 int pass_len,
-                                                 pem_password_cb *cb, void *u);
-
-OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x,
-                                                pem_password_cb *cb, void *u);
-
-OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey(FILE *fp, const EVP_PKEY *x,
-                                             const EVP_CIPHER *enc,
-                                             const char *pass, int pass_len,
-                                             pem_password_cb *cd, void *u);
-
-
 #if defined(__cplusplus)
 }  // extern C
 #endif
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index ff27b47..8c81152 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1906,8 +1906,6 @@
 // connections within an application-level session will reuse TLS sessions. TLS
 // sessions may be dropped by the client or ignored by the server at any time.
 
-DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
-
 // SSL_SESSION_new returns a newly-allocated blank `SSL_SESSION` or NULL on
 // error. This may be useful when writing tests but should otherwise not be
 // used.
@@ -1940,6 +1938,27 @@
                                                    size_t in_len,
                                                    const SSL_CTX *ctx);
 
+// PEM_read_bio_SSL_SESSION reads an `SSL_SESSION` as a PEM block of type "SSL
+// SESSION PARAMETERS", as described in `PEM_read_bio_SAMPLE`.
+OPENSSL_EXPORT SSL_SESSION *PEM_read_bio_SSL_SESSION(BIO *bio,
+                                                     SSL_SESSION **out,
+                                                     pem_password_cb *cb,
+                                                     void *userdata);
+
+// PEM_read_SSL_SESSION behaves like `PEM_read_bio_SSL_SESSION` but reads from
+// `fp`.
+OPENSSL_EXPORT SSL_SESSION *PEM_read_SSL_SESSION(FILE *fp, SSL_SESSION **out,
+                                                 pem_password_cb *cb,
+                                                 void *userdata);
+
+// PEM_write_bio_SSL_SESSION writes `in` to `bio` as a PEM block of type "SSL
+// SESSION PARAMETERS", as described in `PEM_write_bio_SAMPLE`.
+OPENSSL_EXPORT int PEM_write_bio_SSL_SESSION(BIO *bio, const SSL_SESSION *in);
+
+// PEM_write_SSL_SESSION behaves like `PEM_write_bio_SSL_SESSION` but writes to
+// `fp`.
+OPENSSL_EXPORT int PEM_write_SSL_SESSION(FILE *fp, const SSL_SESSION *in);
+
 // SSL_SESSION_get_version returns a string describing the TLS or DTLS version
 // `session` was established at. For example, "TLSv1.2" or "DTLSv1".
 OPENSSL_EXPORT const char *SSL_SESSION_get_version(const SSL_SESSION *session);