Add PEM_bytes_read_bio_secmem()
authorBenjamin Kaduk <bkaduk@akamai.com>
Mon, 29 Feb 2016 21:47:12 +0000 (15:47 -0600)
committerRichard Levitte <levitte@openssl.org>
Mon, 8 May 2017 19:20:31 +0000 (21:20 +0200)
Split the PEM_bytes_read_bio() implementation out into a
pem_bytes_read_bio_flags() helper, to allow it to pass PEM_FLAG_SECURE
as needed.  Adjust the cleanup to properly use OPENSSL_secure_free()
when needed, and reimplement PEM_bytes_read() as a wrapper around
the _flags helper.

Add documentation for PEM_bytes_read_bio() and the new secmem variant.

Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/1700)

crypto/pem/pem_lib.c
doc/man3/PEM_bytes_read_bio.pod [new file with mode: 0644]
include/openssl/pem.h
util/libcrypto.num

index 2432013..75b022e 100644 (file)
@@ -242,9 +242,10 @@ static void *pem_malloc(int num, unsigned int flags)
                                      : OPENSSL_malloc(num);
 }
 
-int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
-                       const char *name, BIO *bp, pem_password_cb *cb,
-                       void *u)
+static int pem_bytes_read_bio_flags(unsigned char **pdata, long *plen,
+                                    char **pnm, const char *name, BIO *bp,
+                                    pem_password_cb *cb, void *u,
+                                    unsigned int flags)
 {
     EVP_CIPHER_INFO cipher;
     char *nm = NULL, *header = NULL;
@@ -252,18 +253,16 @@ int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
     long len;
     int ret = 0;
 
-    for (;;) {
-        if (!PEM_read_bio(bp, &nm, &header, &data, &len)) {
+    do {
+        pem_free(nm, flags);
+        pem_free(header, flags);
+        pem_free(data, flags);
+        if (!PEM_read_bio_ex(bp, &nm, &header, &data, &len, flags)) {
             if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE)
                 ERR_add_error_data(2, "Expecting: ", name);
             return 0;
         }
-        if (check_pem(nm, name))
-            break;
-        OPENSSL_free(nm);
-        OPENSSL_free(header);
-        OPENSSL_free(data);
-    }
+    } while (!check_pem(nm, name));
     if (!PEM_get_EVP_CIPHER_INFO(header, &cipher))
         goto err;
     if (!PEM_do_header(&cipher, data, &len, cb, u))
@@ -272,20 +271,34 @@ int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
     *pdata = data;
     *plen = len;
 
-    if (pnm)
+    if (pnm != NULL)
         *pnm = nm;
 
     ret = 1;
 
  err:
-    if (!ret || !pnm)
-        OPENSSL_free(nm);
-    OPENSSL_free(header);
+    if (!ret || pnm == NULL)
+        pem_free(nm, flags);
+    pem_free(header, flags);
     if (!ret)
-        OPENSSL_free(data);
+        pem_free(data, flags);
     return ret;
 }
 
+int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
+                       const char *name, BIO *bp, pem_password_cb *cb,
+                       void *u) {
+    return pem_bytes_read_bio_flags(pdata, plen, pnm, name, bp, cb, u,
+                                    PEM_FLAG_EAY_COMPATIBLE);
+}
+
+int PEM_bytes_read_bio_secmem(unsigned char **pdata, long *plen, char **pnm,
+                              const char *name, BIO *bp, pem_password_cb *cb,
+                              void *u) {
+    return pem_bytes_read_bio_flags(pdata, plen, pnm, name, bp, cb, u,
+                                    PEM_FLAG_SECURE | PEM_FLAG_EAY_COMPATIBLE);
+}
+
 #ifndef OPENSSL_NO_STDIO
 int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
                    void *x, const EVP_CIPHER *enc, unsigned char *kstr,
diff --git a/doc/man3/PEM_bytes_read_bio.pod b/doc/man3/PEM_bytes_read_bio.pod
new file mode 100644 (file)
index 0000000..d16ccd8
--- /dev/null
@@ -0,0 +1,81 @@
+=pod
+
+=head1 NAME
+
+PEM_bytes_read_bio, PEM_bytes_read_bio_secmem - read a PEM-encoded data structure from a BIO
+
+=head1 SYNOPSIS
+
+ #include <openssl/pem.h>
+
+ int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
+                        const char *name, BIO *bp, pem_password_cb *cb,
+                        void *u);
+ int PEM_bytes_read_bio_secmem(unsigned char **pdata, long *plen, char **pnm,
+                               const char *name, BIO *bp, pem_password_cb *cb,
+                               void *u);
+
+=head1 DESCRIPTION
+
+PEM_bytes_read_bio() reads PEM-formatted (RFC 1421) data from the BIO
+I<bp> for the data type given in I<name> (RSA PRIVATE KEY, CERTIFICATE,
+etc.).  If multiple PEM-encoded data structures are present in the same
+stream, PEM_bytes_read_bio() will skip non-matching data types and
+continue reading.  Non-PEM data present in the stream may cause an
+error.
+
+The PEM header may indicate that the following data is encrypted; if so,
+the data will be decrypted, waiting on user input to supply a passphrase
+if needed.  The password callback I<cb> and rock I<u> are used to obtain
+the decryption passphrase, if applicable.
+
+Some data types have compatibility aliases, such as a file containing
+X509 CERTIFICATE matching a request for the deprecated type CERTIFICATE.
+The actual type indicated by the file is returned in I<*pnm> if I<pnm> is
+non-NULL.  The caller must free the storage pointed to by I<*pnm>.
+
+The returned data is the DER-encoded form of the requested type, in
+I<*pdata> with length I<*plen>.  The caller must free the storage pointed
+to by I<*pdata>.
+
+PEM_bytes_read_bio_secmem() is similar to PEM_bytes_read_bio(), but uses
+memory from the secure heap for its temporary buffers and the storage
+returned in I<*pdata> and I<*pnm>.  Accordingly, the caller must use
+OPENSSL_secure_free() to free that storage.
+
+=head1 NOTES
+
+PEM_bytes_read_bio_secmem() only enforces that the secure heap is used for
+storage allocated within the PEM processing stack.  The BIO stack from
+which input is read may also use temporary buffers, which are not necessarily
+allocated from the secure heap.  In cases where it is desirable to ensure
+that the contents of the PEM file only appears in memory from the secure heap,
+care is needed in generating the BIO passed as I<bp>.  In particular, the
+use of BIO_s_file() indicates the use of the operating system stdio
+functionality, which includes buffering as a feature; BIO_s_fd() is likely
+to be more appropriate in such cases.
+
+=head1 RETURN VALUES
+
+PEM_bytes_read_bio() and PEM_bytes_read_bio_secmem() return 1 for success or
+0 for failure.
+
+=head1 SEE ALSO
+
+L<PEM(3)>,
+L<PEM_read_bio_ex(3)>
+
+=head1 HISTORY
+
+PEM_bytes_read_bio_secmem() was introduced in OpenSSL 1.1.1
+
+=head1 COPYRIGHT
+
+Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
index d6f76eb..105c810 100644 (file)
@@ -241,6 +241,9 @@ int PEM_read_bio(BIO *bp, char **name, char **header,
 #   define PEM_FLAG_ONLY_B64           0x4
 int PEM_read_bio_ex(BIO *bp, char **name, char **header,
                     unsigned char **data, long *len, unsigned int flags);
+int PEM_bytes_read_bio_secmem(unsigned char **pdata, long *plen, char **pnm,
+                              const char *name, BIO *bp, pem_password_cb *cb,
+                              void *u);
 int PEM_write_bio(BIO *bp, const char *name, const char *hdr,
                   const unsigned char *data, long len);
 int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
index fa14ab4..d6c122d 100644 (file)
@@ -4289,3 +4289,4 @@ ESS_SIGNING_CERT_V2_free                4231      1_1_1   EXIST::FUNCTION:TS
 ESS_SIGNING_CERT_V2_dup                 4232   1_1_1   EXIST::FUNCTION:TS
 ESS_CERT_ID_V2_new                      4233   1_1_1   EXIST::FUNCTION:TS
 PEM_read_bio_ex                         4234   1_1_1   EXIST::FUNCTION:
+PEM_bytes_read_bio_secmem               4235   1_1_1   EXIST::FUNCTION: