Start expanding and documenting PEM_read and PEM_write functions

Like asn1.h and x509.h, this starts the process of expanding the
functions hidden inside macros so that we can document them properly. To
capture the many common conventions, have a sample block (matching what
we did for asn1.h). I've done a handful of types to start with, so we
can settle on the pattern to use.

I'm thinking we'll start with these sections, put all the type-specific
ones there, and then have a "Low-level functions" or "Reading and
writing raw PEM blocks" or whatever for the rest.

Bug: 42290574
Change-Id: I50fce8d4433c7fc676b5d187a518f23a25bdac17
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/97227
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
diff --git a/crypto/pem/pem_lib.cc b/crypto/pem/pem_lib.cc
index 5385049..a5f57ee 100644
--- a/crypto/pem/pem_lib.cc
+++ b/crypto/pem/pem_lib.cc
@@ -266,7 +266,7 @@
       if (!callback) {
         callback = PEM_def_callback;
       }
-      pass_len = (*callback)(buf, PEM_BUFSIZE, 1, u);
+      pass_len = (*callback)(buf, PEM_BUFSIZE, /*enc=*/1, u);
       if (pass_len < 0) {
         OPENSSL_PUT_ERROR(PEM, PEM_R_READ_KEY);
         goto err;
@@ -337,7 +337,7 @@
   if (!callback) {
     callback = PEM_def_callback;
   }
-  pass_len = callback(buf, PEM_BUFSIZE, 0, u);
+  pass_len = callback(buf, PEM_BUFSIZE, /*enc=*/0, u);
   if (pass_len < 0) {
     OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ);
     return 0;
@@ -714,7 +714,7 @@
   return 1;
 }
 
-int PEM_def_callback(char *buf, int size, int rwflag, void *userdata) {
+int PEM_def_callback(char *buf, int size, int enc, void *userdata) {
   if (!buf || !userdata || size < 0) {
     return -1;
   }
diff --git a/include/openssl/pem.h b/include/openssl/pem.h
index 7dc418a..b2b758f 100644
--- a/include/openssl/pem.h
+++ b/include/openssl/pem.h
@@ -36,11 +36,186 @@
 // PEM.
 //
 // This library contains functions for reading and writing data encoded in PEM
-// format. This format originated in Privacy-Enhanced Mail (RFC 1421).
+// format. This format originated in Privacy-Enhanced Mail (RFC 1421). PEM
+// consists of a series of PEM blocks, which are line-wrapped, base64-encoded
+// data, wrapped in BEGIN and END lines, for example:
 //
-// TODO(crbug.com/42290574): Finish documenting this header.
+//   -----BEGIN PUBLIC KEY-----
+//   MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=
+//   -----END PUBLIC KEY-----
+//
+// The BEGIN and END markers specify the type of data encoded. Multiple PEM
+// blocks can be concatenated together. For example, it is common to represent a
+// certificate chain as a series of PEM blocks of type CERTIFICATE. Owing to its
+// email roots, PEM blocks can also be embedded in non-PEM data. The parsers in
+// this library will generally skip over any non-PEM data, as well as any PEM
+// blocks that are not of the expected type.
+//
+// PEM blocks can be encrypted with a password, specified in RFC 1423. PEM
+// encryption is vulnerable to padding oracle attacks and should not be used as
+// a load-bearing security measure. It is implemented for interoperability with
+// legacy systems only.
+//
+// Callers should only use PEM for compatibility with legacy systems. PEM use
+// should be limited to the components that directly interoperate with those
+// systems, converting to and from more modern formats. PEM adds overhead to fit
+// in email's 7-bit ASCII limitations, a constraint that is not relevant to most
+// applications.
 
 
+// API conventions.
+
+// pem_password_cb is an application-supplied callback to supply a PEM password.
+// On success, the callback should write the password into `out`, which has room
+// for at most `max_out` bytes. On error, including if `max_out` is too small,
+// it should return -1. `enc` is one if the password will be used for encrypting
+// and zero if it is used for decrypting. `userdata` is the application-supplied
+// parameter of the same name to the PEM function.
+typedef int pem_password_cb(char *out, int max_out, int enc, void *userdata);
+
+// PEM_def_callback is the default implementation of `pem_password_cb`. It
+// interprets `userdata` as a NUL-terminated C string and outputs it according
+// to `pem_password_cb`. If `userdata` is NULL, it returns -1.
+//
+// This differs from OpenSSL, which interactively prompts for a password by
+// default.
+OPENSSL_EXPORT int PEM_def_callback(char *buf, int size, int enc,
+                                    void *userdata);
+
+// The following sample functions document the calling conventions used by this
+// library.
+
+#if 0  // Sample functions
+
+// PEM_read_bio_SAMPLE reads a PEM block from `bio`, skipping non-PEM data and
+// unexpected block types. It then decodes the resulting PEM block and returns a
+// newly-allocated `SAMPLE` object containing the parsed structure. If `out` is
+// non-NULL, it additionally frees the previous value at `*out` and updates
+// `*out` to the result.
+//
+// On decode or allocation error, or if EOF is reached before a matching PEM
+// block is found, it returns NULL. In the error case, it will add
+// `PEM_R_NO_START_LINE` to the error queue. Callers can check the error queue
+// to distinguish these cases.
+//
+// If the PEM block is encrypted, `cb` will be called to look up the password.
+// See `pem_password_cb` for details. If `cb` is NULL, `PEM_def_callback` is
+// used and `userdata` should be a NUL-terminated C string containing the
+// password. Set both `cb` and `userdata` to NULL to only handle plaintext
+// blocks.
+SAMPLE *PEM_read_bio_SAMPLE(BIO *bio, SAMPLE **out, pem_password_cb *cb,
+                            void *userdata);
+
+// PEM_write_bio_SAMPLE encodes `in` as a PEM block and writes it to `bio`. It
+// returns one on success and zero on error.
+//
+// If `enc` is non-NULL, the PEM block is encrypted with the specified cipher
+// and a password. If `pass` is non-NULL, `pass_len` bytes from `pass` is
+// used as the password. Otherwise, `cb` is called. If `cb` is NULL,
+// `PEM_def_callback` is used. PEM encryption is vulnerable to padding oracle
+// attacks and should not be used.
+//
+// Some functions of this convention do not support encryption. In this case,
+// the encryption-related parameters will be omitted.
+//
+// On error, the state of `bio` is undefined. It is possible a prefix of a PEM
+// block was left in the `bio`.
+int PEM_write_bio_SAMPLE(BIO *bio, const SAMPLE *in, const EVP_CIPHER *enc,
+                         const uint8_t *pass, int pass_len, pem_password_cb *cb,
+                         void *userdata);
+
+#endif  // Sample functions
+
+
+// Reading and writing objects as PEM.
+
+// PEM_read_bio_X509 reads a PEM block of type "CERTIFICATE" 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`.
+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_SAMPLE`.
+//
+// WARNING: This function parses auxiliary properties as in `d2i_X509_AUX`.
+// Passing untrusted input to this function allows an attacker to influence
+// those properties. See `d2i_X509_AUX` for details.
+OPENSSL_EXPORT X509 *PEM_read_bio_X509_AUX(BIO *bio, X509 **out,
+                                           pem_password_cb *cb, void *userdata);
+
+// PEM_write_bio_X509_AUX writes a PEM block of type "TRUSTED CERTIFICATE", as
+// described in `PEM_write_bio_SAMPLE`.
+//
+// WARNING: This function writes a custom OpenSSL-specific format that includes
+// 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`.
+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
+// certificates, CRLs, and private keys found. It returns a
+// `STACK_OF(X509_INFO)` structure containing the results, or NULL on error.
+//
+// If `sk` is NULL, the result on success will be a newly-allocated
+// `STACK_OF(X509_INFO)` structure which should be released with
+// `sk_X509_INFO_pop_free` and `X509_INFO_free` when done.
+//
+// If `sk` is non-NULL, it appends the results to `sk` instead and returns `sk`
+// 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`,
+// 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
+// certificates, but encrypted passwords, without knowing the password. However,
+// it also means that this function cannot be used to decrypt the private key
+// when the password is known.
+//
+// WARNING: If the input contains "TRUSTED CERTIFICATE" PEM blocks, this
+// function parses auxiliary properties as in `d2i_X509_AUX`. Passing untrusted
+// 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);
+
+// The following functions behave like corresponding `PEM_read_bio_*` function,
+// 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,
+                                           pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT X509 *PEM_read_X509_AUX(FILE *fp, X509 **out,
+                                       pem_password_cb *cb, void *userdata);
+OPENSSL_EXPORT STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp,
+                                                       STACK_OF(X509_INFO) *sk,
+                                                       pem_password_cb *cb,
+                                                       void *userdata);
+
+// The following functions behave like corresponding `PEM_write_bio_*` function,
+// 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);
+
+
+// Not yet documented functions.
+//
+// TODO(crbug.com/42290574): Finish documenting and organizing this header.
+
 #define PEM_BUFSIZE 1024
 
 #define PEM_STRING_X509_OLD "X509 CERTIFICATE"
@@ -73,29 +248,31 @@
 #define PEM_TYPE_MIC_CLEAR 30
 #define PEM_TYPE_CLEAR 40
 
-#define DECLARE_PEM_read_fp(name, type)                    \
-  OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, \
-                                       pem_password_cb *cb, void *u);
+#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 *x);
+  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 *x, const EVP_CIPHER *enc, \
-      const unsigned char *pass, int pass_len, pem_password_cb *cb, void *u);
+#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 *bp, type **x, \
-                                           pem_password_cb *cb, void *u);
+#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 *bp, const type *x);
+  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 *bp, const type *x, const EVP_CIPHER *enc, \
-      const unsigned char *pass, int pass_len, pem_password_cb *cb, void *u);
+#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)   \
@@ -117,9 +294,6 @@
   DECLARE_PEM_read(name, type)        \
   DECLARE_PEM_write_cb(name, type)
 
-// "userdata": new with OpenSSL 0.9.4
-typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata);
-
 // PEM_read_bio reads from `bp`, until the next PEM block. If one is found, it
 // returns one and sets `*name`, `*header`, and `*data` to newly-allocated
 // buffers containing the PEM type, the header block, and the decoded data,
@@ -151,40 +325,6 @@
                                       const unsigned char *pass, int pass_len,
                                       pem_password_cb *cb, void *u);
 
-// PEM_X509_INFO_read_bio reads PEM blocks from `bp` and decodes any
-// certificates, CRLs, and private keys found. It returns a
-// `STACK_OF(X509_INFO)` structure containing the results, or NULL on error.
-//
-// If `sk` is NULL, the result on success will be a newly-allocated
-// `STACK_OF(X509_INFO)` structure which should be released with
-// `sk_X509_INFO_pop_free` and `X509_INFO_free` when done.
-//
-// If `sk` is non-NULL, it appends the results to `sk` instead and returns `sk`
-// 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`,
-// 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
-// certificates, but encrypted passwords, without knowing the password. However,
-// it also means that this function cannot be used to decrypt the private key
-// when the password is known.
-//
-// WARNING: If the input contains "TRUSTED CERTIFICATE" PEM blocks, this
-// function parses auxiliary properties as in `d2i_X509_AUX`. Passing untrusted
-// 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 *u);
-
-// PEM_X509_INFO_read behaves like `PEM_X509_INFO_read_bio` but reads from a
-// `FILE`.
-OPENSSL_EXPORT STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp,
-                                                       STACK_OF(X509_INFO) *sk,
-                                                       pem_password_cb *cb,
-                                                       void *u);
-
 OPENSSL_EXPORT int PEM_read(FILE *fp, char **name, char **header,
                             unsigned char **data, long *len);
 OPENSSL_EXPORT int PEM_write(FILE *fp, const char *name, const char *hdr,
@@ -196,25 +336,10 @@
                                   const unsigned char *pass, int pass_len,
                                   pem_password_cb *callback, void *u);
 
-// PEM_def_callback treats `userdata` as a string and copies it into `buf`,
-// assuming its `size` is sufficient. Returns the length of the string, or -1 on
-// error. Error cases the buffer being too small, or `buf` and `userdata` being
-// NULL. Note that this is different from OpenSSL, which prompts for a password.
-OPENSSL_EXPORT int PEM_def_callback(char *buf, int size, int rwflag,
-                                    void *userdata);
-
-
-DECLARE_PEM_rw(X509, X509)
-
-// TODO(crbug.com/boringssl/426): When documenting these, copy the warning
-// about auxiliary properties from `PEM_X509_INFO_read_bio`.
-
-DECLARE_PEM_rw(X509_AUX, X509)
 
 DECLARE_PEM_rw(X509_REQ, X509_REQ)
 DECLARE_PEM_write(X509_REQ_NEW, X509_REQ)
 
-DECLARE_PEM_rw(X509_CRL, X509_CRL)
 
 DECLARE_PEM_rw(PKCS7, PKCS7)
 DECLARE_PEM_rw(PKCS8, X509_SIG)
@@ -226,16 +351,12 @@
 DECLARE_PEM_rw(RSAPublicKey, RSA)
 DECLARE_PEM_rw(RSA_PUBKEY, RSA)
 
-#ifndef OPENSSL_NO_DSA
-
 DECLARE_PEM_rw_cb(DSAPrivateKey, DSA)
 
 DECLARE_PEM_rw(DSA_PUBKEY, DSA)
 
 DECLARE_PEM_rw(DSAparams, DSA)
 
-#endif
-
 DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY)
 DECLARE_PEM_rw(EC_PUBKEY, EC_KEY)