Don't mutate the buffer in PEM_get_EVP_CIPHER_INFO

There's a lot more we could improve in this function, but fix this
particular egregious issue first.

Change-Id: Idc4b7f9aa62972293ead4f8534b8461942318e21
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/74808
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/pem/internal.h b/crypto/pem/internal.h
index 3cfc8ac..9fe9a5b 100644
--- a/crypto/pem/internal.h
+++ b/crypto/pem/internal.h
@@ -22,10 +22,7 @@
 // error. |header| must be a NUL-terminated string. If |header| does not
 // specify encryption, this function will return success and set
 // |cipher->cipher| to NULL.
-//
-// WARNING: This function will internally write to the string pointed by
-// |header|. |header| must not point to constant storage.
-int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher);
+int PEM_get_EVP_CIPHER_INFO(const char *header, EVP_CIPHER_INFO *cipher);
 
 // PEM_do_header decrypts |*len| bytes from |data| in-place according to the
 // information in |cipher|. On success, it returns one and sets |*len| to the
diff --git a/crypto/pem/pem_lib.cc b/crypto/pem/pem_lib.cc
index 69980fe..34048a3 100644
--- a/crypto/pem/pem_lib.cc
+++ b/crypto/pem/pem_lib.cc
@@ -12,6 +12,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <string_view>
+
 #include <openssl/base64.h>
 #include <openssl/buf.h>
 #include <openssl/des.h>
@@ -29,7 +31,7 @@
 
 #define MIN_LENGTH 4
 
-static int load_iv(char **fromp, unsigned char *to, size_t num);
+static int load_iv(const char **fromp, unsigned char *to, size_t num);
 static int check_pem(const char *nm, const char *name);
 
 // PEM_proc_type appends a Proc-Type header to |buf|, determined by |type|.
@@ -143,19 +145,19 @@
   return 0;
 }
 
-static const EVP_CIPHER *cipher_by_name(const char *name) {
+static const EVP_CIPHER *cipher_by_name(std::string_view name) {
   // This is similar to the (deprecated) function |EVP_get_cipherbyname|. Note
   // the PEM code assumes that ciphers have at least 8 bytes of IV, at most 20
   // bytes of overhead and generally behave like CBC mode.
-  if (0 == strcmp(name, SN_des_cbc)) {
+  if (name == SN_des_cbc) {
     return EVP_des_cbc();
-  } else if (0 == strcmp(name, SN_des_ede3_cbc)) {
+  } else if (name == SN_des_ede3_cbc) {
     return EVP_des_ede3_cbc();
-  } else if (0 == strcmp(name, SN_aes_128_cbc)) {
+  } else if (name == SN_aes_128_cbc) {
     return EVP_aes_128_cbc();
-  } else if (0 == strcmp(name, SN_aes_192_cbc)) {
+  } else if (name == SN_aes_192_cbc) {
     return EVP_aes_192_cbc();
-  } else if (0 == strcmp(name, SN_aes_256_cbc)) {
+  } else if (name == SN_aes_256_cbc) {
     return EVP_aes_256_cbc();
   } else {
     return NULL;
@@ -377,11 +379,7 @@
   return 1;
 }
 
-int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher) {
-  const EVP_CIPHER *enc = NULL;
-  char *p, c;
-  char **header_pp = &header;
-
+int PEM_get_EVP_CIPHER_INFO(const char *header, EVP_CIPHER_INFO *cipher) {
   cipher->cipher = NULL;
   OPENSSL_memset(cipher->iv, 0, sizeof(cipher->iv));
   if ((header == NULL) || (*header == '\0') || (*header == '\n')) {
@@ -418,40 +416,38 @@
   }
   header += 10;
 
-  p = header;
+  const char *p = header;
   for (;;) {
-    c = *header;
+    char c = *header;
     if (!((c >= 'A' && c <= 'Z') || c == '-' || OPENSSL_isdigit(c))) {
       break;
     }
     header++;
   }
-  *header = '\0';
-  cipher->cipher = enc = cipher_by_name(p);
-  *header = c;
+  cipher->cipher = cipher_by_name(std::string_view(p, header - p));
   header++;
-
-  if (enc == NULL) {
+  if (cipher->cipher == NULL) {
     OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_ENCRYPTION);
     return 0;
   }
   // The IV parameter must be at least 8 bytes long to be used as the salt in
   // the KDF. (This should not happen given |cipher_by_name|.)
-  if (EVP_CIPHER_iv_length(enc) < 8) {
+  if (EVP_CIPHER_iv_length(cipher->cipher) < 8) {
     assert(0);
     OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_ENCRYPTION);
     return 0;
   }
-  if (!load_iv(header_pp, &(cipher->iv[0]), EVP_CIPHER_iv_length(enc))) {
+  const char **header_pp = &header;
+  if (!load_iv(header_pp, cipher->iv, EVP_CIPHER_iv_length(cipher->cipher))) {
     return 0;
   }
 
   return 1;
 }
 
-static int load_iv(char **fromp, unsigned char *to, size_t num) {
+static int load_iv(const char **fromp, unsigned char *to, size_t num) {
   uint8_t v;
-  char *from;
+  const char *from;
 
   from = *fromp;
   for (size_t i = 0; i < num; i++) {