In cases where we ask PEM_def_callback for minimum 0 length, accept 0 length
[openssl.git] / crypto / pem / pem_lib.c
index f18dcca35784afd8ab8e2af68741286597063ba6..7c82561ba40ee53031aab3af03325a904675e1fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 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
@@ -8,7 +8,7 @@
  */
 
 #include <stdio.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include <string.h>
 #include "internal/cryptlib.h"
 #include <openssl/buffer.h>
@@ -28,15 +28,16 @@ static int load_iv(char **fromp, unsigned char *to, int num);
 static int check_pem(const char *nm, const char *name);
 int pem_check_suffix(const char *pem_str, const char *suffix);
 
-int PEM_def_callback(char *buf, int num, int w, void *key)
+int PEM_def_callback(char *buf, int num, int rwflag, void *userdata)
 {
-    int i, j;
+    int i, min_len;
     const char *prompt;
 
-    if (key) {
-        i = strlen(key);
+    /* We assume that the user passes a default password as userdata */
+    if (userdata) {
+        i = strlen(userdata);
         i = (i > num) ? num : i;
-        memcpy(buf, key, i);
+        memcpy(buf, userdata, i);
         return i;
     }
 
@@ -44,33 +45,28 @@ int PEM_def_callback(char *buf, int num, int w, void *key)
     if (prompt == NULL)
         prompt = "Enter PEM pass phrase:";
 
-    for (;;) {
-        /*
-         * We assume that w == 0 means decryption,
-         * while w == 1 means encryption
-         */
-        int min_len = w ? MIN_LENGTH : 0;
+    /*
+     * rwflag == 0 means decryption
+     * rwflag == 1 means encryption
+     *
+     * We assume that for encryption, we want a minimum length, while for
+     * decryption, we cannot know any minimum length, so we assume zero.
+     */
+    min_len = rwflag ? MIN_LENGTH : 0;
 
-        i = EVP_read_pw_string_min(buf, min_len, num, prompt, w);
-        if (i != 0) {
-            PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD);
-            memset(buf, 0, (unsigned int)num);
-            return -1;
-        }
-        j = strlen(buf);
-        if (min_len && j < min_len) {
-            fprintf(stderr,
-                    "phrase is too short, needs to be at least %d chars\n",
-                    min_len);
-        } else
-            break;
+    i = EVP_read_pw_string_min(buf, min_len, num, prompt, rwflag);
+    if (i != 0) {
+        PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD);
+        memset(buf, 0, (unsigned int)num);
+        return -1;
     }
-    return j;
+    return strlen(buf);
 }
 
 void PEM_proc_type(char *buf, int type)
 {
     const char *str;
+    char *p = buf + strlen(buf);
 
     if (type == PEM_TYPE_ENCRYPTED)
         str = "ENCRYPTED";
@@ -81,27 +77,29 @@ void PEM_proc_type(char *buf, int type)
     else
         str = "BAD-TYPE";
 
-    strcat(buf, "Proc-Type: 4,");
-    strcat(buf, str);
-    strcat(buf, "\n");
+    BIO_snprintf(p, PEM_BUFSIZE - (size_t)(p - buf), "Proc-Type: 4,%s\n", str);
 }
 
 void PEM_dek_info(char *buf, const char *type, int len, char *str)
 {
-    static const unsigned char map[17] = "0123456789ABCDEF";
     long i;
-    int j;
-
-    strcat(buf, "DEK-Info: ");
-    strcat(buf, type);
-    strcat(buf, ",");
-    j = strlen(buf);
-    for (i = 0; i < len; i++) {
-        buf[j + i * 2] = map[(str[i] >> 4) & 0x0f];
-        buf[j + i * 2 + 1] = map[(str[i]) & 0x0f];
-    }
-    buf[j + i * 2] = '\n';
-    buf[j + i * 2 + 1] = '\0';
+    char *p = buf + strlen(buf);
+    int j = PEM_BUFSIZE - (size_t)(p - buf), n;
+
+    n = BIO_snprintf(p, j, "DEK-Info: %s,", type);
+    if (n > 0) {
+        j -= n;
+        p += n;
+        for (i = 0; i < len; i++) {
+            n = BIO_snprintf(p, j, "%02X", 0xff & str[i]);
+            if (n <= 0)
+                return;
+            j -= n;
+            p += n;
+        }
+        if (j > 1)
+            strcpy(p, "\n");
+    }
 }
 
 #ifndef OPENSSL_NO_STDIO
@@ -113,12 +111,12 @@ void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
 
     if ((b = BIO_new(BIO_s_file())) == NULL) {
         PEMerr(PEM_F_PEM_ASN1_READ, ERR_R_BUF_LIB);
-        return (0);
+        return 0;
     }
     BIO_set_fp(b, fp, BIO_NOCLOSE);
     ret = PEM_ASN1_read_bio(d2i, name, b, x, cb, u);
     BIO_free(b);
-    return (ret);
+    return ret;
 }
 #endif
 
@@ -217,10 +215,10 @@ static int check_pem(const char *nm, const char *name)
     return 0;
 }
 
-static void pem_free(void *p, unsigned int flags)
+static void pem_free(void *p, unsigned int flags, size_t num)
 {
     if (flags & PEM_FLAG_SECURE)
-        OPENSSL_secure_free(p);
+        OPENSSL_secure_clear_free(p, num);
     else
         OPENSSL_free(p);
 }
@@ -239,13 +237,13 @@ static int pem_bytes_read_bio_flags(unsigned char **pdata, long *plen,
     EVP_CIPHER_INFO cipher;
     char *nm = NULL, *header = NULL;
     unsigned char *data = NULL;
-    long len;
+    long len = 0;
     int ret = 0;
 
     do {
-        pem_free(nm, flags);
-        pem_free(header, flags);
-        pem_free(data, flags);
+        pem_free(nm, flags, 0);
+        pem_free(header, flags, 0);
+        pem_free(data, flags, len);
         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);
@@ -267,10 +265,10 @@ static int pem_bytes_read_bio_flags(unsigned char **pdata, long *plen,
 
  err:
     if (!ret || pnm == NULL)
-        pem_free(nm, flags);
-    pem_free(header, flags);
+        pem_free(nm, flags, 0);
+    pem_free(header, flags, 0);
     if (!ret)
-        pem_free(data, flags);
+        pem_free(data, flags, len);
     return ret;
 }
 
@@ -298,12 +296,12 @@ int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
 
     if ((b = BIO_new(BIO_s_file())) == NULL) {
         PEMerr(PEM_F_PEM_ASN1_WRITE, ERR_R_BUF_LIB);
-        return (0);
+        return 0;
     }
     BIO_set_fp(b, fp, BIO_NOCLOSE);
     ret = PEM_ASN1_write_bio(i2d, name, b, x, enc, kstr, klen, callback, u);
     BIO_free(b);
-    return (ret);
+    return ret;
 }
 #endif
 
@@ -321,7 +319,14 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
 
     if (enc != NULL) {
         objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc));
-        if (objstr == NULL || EVP_CIPHER_iv_length(enc) == 0) {
+        if (objstr == NULL || EVP_CIPHER_iv_length(enc) == 0
+                || EVP_CIPHER_iv_length(enc) > (int)sizeof(iv)
+                   /*
+                    * Check "Proc-Type: 4,Encrypted\nDEK-Info: objstr,hex-iv\n"
+                    * fits into buf
+                    */
+                || (strlen(objstr) + 23 + 2 * EVP_CIPHER_iv_length(enc) + 13)
+                   > sizeof(buf)) {
             PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, PEM_R_UNSUPPORTED_CIPHER);
             goto err;
         }
@@ -358,8 +363,6 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
 #endif
             kstr = (unsigned char *)buf;
         }
-        RAND_add(data, i, 0);   /* put in the RSA key. */
-        OPENSSL_assert(EVP_CIPHER_iv_length(enc) <= (int)sizeof(iv));
         if (RAND_bytes(iv, EVP_CIPHER_iv_length(enc)) <= 0) /* Generate a salt */
             goto err;
         /*
@@ -372,9 +375,6 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
         if (kstr == (unsigned char *)buf)
             OPENSSL_cleanse(buf, PEM_BUFSIZE);
 
-        OPENSSL_assert(strlen(objstr) + 23 + 2 * EVP_CIPHER_iv_length(enc) + 13
-                       <= sizeof buf);
-
         buf[0] = '\0';
         PEM_proc_type(buf, PEM_TYPE_ENCRYPTED);
         PEM_dek_info(buf, objstr, EVP_CIPHER_iv_length(enc), (char *)iv);
@@ -402,7 +402,7 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
     EVP_CIPHER_CTX_free(ctx);
     OPENSSL_cleanse(buf, PEM_BUFSIZE);
     OPENSSL_clear_free(data, (unsigned int)dsize);
-    return (ret);
+    return ret;
 }
 
 int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen,
@@ -430,7 +430,7 @@ int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen,
         keylen = PEM_def_callback(buf, PEM_BUFSIZE, 0, u);
     else
         keylen = callback(buf, PEM_BUFSIZE, 0, u);
-    if (keylen <= 0) {
+    if (keylen < 0) {
         PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_PASSWORD_READ);
         return 0;
     }
@@ -570,14 +570,14 @@ static int load_iv(char **fromp, unsigned char *to, int num)
         v = OPENSSL_hexchar2int(*from);
         if (v < 0) {
             PEMerr(PEM_F_LOAD_IV, PEM_R_BAD_IV_CHARS);
-            return (0);
+            return 0;
         }
         from++;
         to[i / 2] |= v << (long)((!(i & 1)) * 4);
     }
 
     *fromp = from;
-    return (1);
+    return 1;
 }
 
 #ifndef OPENSSL_NO_STDIO
@@ -589,12 +589,12 @@ int PEM_write(FILE *fp, const char *name, const char *header,
 
     if ((b = BIO_new(BIO_s_file())) == NULL) {
         PEMerr(PEM_F_PEM_WRITE, ERR_R_BUF_LIB);
-        return (0);
+        return 0;
     }
     BIO_set_fp(b, fp, BIO_NOCLOSE);
     ret = PEM_write_bio(b, name, header, data, len);
     BIO_free(b);
-    return (ret);
+    return ret;
 }
 #endif
 
@@ -605,6 +605,7 @@ int PEM_write_bio(BIO *bp, const char *name, const char *header,
     unsigned char *buf = NULL;
     EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
     int reason = ERR_R_BUF_LIB;
+    int retval = 0;
 
     if (ctx == NULL) {
         reason = ERR_R_MALLOC_FAILURE;
@@ -649,14 +650,14 @@ int PEM_write_bio(BIO *bp, const char *name, const char *header,
         (BIO_write(bp, name, nlen) != nlen) ||
         (BIO_write(bp, "-----\n", 6) != 6))
         goto err;
-    OPENSSL_clear_free(buf, PEM_BUFSIZE * 8);
-    EVP_ENCODE_CTX_free(ctx);
-    return (i + outl);
+    retval = i + outl;
+
  err:
-    OPENSSL_clear_free(buf, PEM_BUFSIZE * 8);
+    if (retval == 0)
+        PEMerr(PEM_F_PEM_WRITE_BIO, reason);
     EVP_ENCODE_CTX_free(ctx);
-    PEMerr(PEM_F_PEM_WRITE_BIO, reason);
-    return (0);
+    OPENSSL_clear_free(buf, PEM_BUFSIZE * 8);
+    return retval;
 }
 
 #ifndef OPENSSL_NO_STDIO
@@ -668,19 +669,16 @@ int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
 
     if ((b = BIO_new(BIO_s_file())) == NULL) {
         PEMerr(PEM_F_PEM_READ, ERR_R_BUF_LIB);
-        return (0);
+        return 0;
     }
     BIO_set_fp(b, fp, BIO_NOCLOSE);
     ret = PEM_read_bio(b, name, header, data, len);
     BIO_free(b);
-    return (ret);
+    return ret;
 }
 #endif
 
 /* Some helpers for PEM_read_bio_ex(). */
-
-#define isb64(c) (isalnum(c) || (c) == '+' || (c) == '/' || (c) == '=')
-
 static int sanitize_line(char *linebuf, int len, unsigned int flags)
 {
     int i;
@@ -693,7 +691,8 @@ static int sanitize_line(char *linebuf, int len, unsigned int flags)
         len++;
     } else if (flags & PEM_FLAG_ONLY_B64) {
         for (i = 0; i < len; ++i) {
-            if (!isb64(linebuf[i]) || linebuf[i] == '\n' || linebuf[i] == '\r')
+            if (!ossl_isbase64(linebuf[i]) || linebuf[i] == '\n'
+                || linebuf[i] == '\r')
                 break;
         }
         len = i;
@@ -703,7 +702,7 @@ static int sanitize_line(char *linebuf, int len, unsigned int flags)
         for (i = 0; i < len; ++i) {
             if (linebuf[i] == '\n' || linebuf[i] == '\r')
                 break;
-            if (iscntrl(linebuf[i]))
+            if (ossl_iscntrl(linebuf[i]))
                 linebuf[i] = ' ';
         }
         len = i;
@@ -719,14 +718,14 @@ static int sanitize_line(char *linebuf, int len, unsigned int flags)
 static const char beginstr[] = "-----BEGIN ";
 static const char endstr[] = "-----END ";
 static const char tailstr[] = "-----\n";
-#define BEGINLEN (sizeof(beginstr) - 1)
-#define ENDLEN (sizeof(endstr) - 1)
-#define TAILLEN (sizeof(tailstr) - 1)
+#define BEGINLEN ((int)(sizeof(beginstr) - 1))
+#define ENDLEN ((int)(sizeof(endstr) - 1))
+#define TAILLEN ((int)(sizeof(tailstr) - 1))
 static int get_name(BIO *bp, char **name, unsigned int flags)
 {
     char *linebuf;
     int ret = 0;
-    size_t len;
+    int len;
 
     /*
      * Need to hold trailing NUL (accounted for by BIO_gets() and the newline
@@ -764,7 +763,7 @@ static int get_name(BIO *bp, char **name, unsigned int flags)
     ret = 1;
 
 err:
-    pem_free(linebuf, flags);
+    pem_free(linebuf, flags, LINESIZE + 1);
     return ret;
 }
 
@@ -856,7 +855,8 @@ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name,
          * Else, a line of text -- could be header or data; we don't
          * know yet.  Just pass it through.
          */
-        BIO_puts(tmp, linebuf);
+        if (BIO_puts(tmp, linebuf) < 0)
+            goto err;
         /*
          * Only encrypted files need the line length check applied.
          */
@@ -871,7 +871,7 @@ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name,
 
     ret = 1;
 err:
-    pem_free(linebuf, flags);
+    pem_free(linebuf, flags, LINESIZE + 1);
     return ret;
 }
 
@@ -939,8 +939,8 @@ int PEM_read_bio_ex(BIO *bp, char **name_out, char **header,
     *header = pem_malloc(headerlen + 1, flags);
     *data = pem_malloc(len, flags);
     if (*header == NULL || *data == NULL) {
-        pem_free(*header, flags);
-        pem_free(*data, flags);
+        pem_free(*header, flags, 0);
+        pem_free(*data, flags, 0);
         goto end;
     }
     BIO_read(headerB, *header, headerlen);
@@ -953,7 +953,7 @@ int PEM_read_bio_ex(BIO *bp, char **name_out, char **header,
 
 end:
     EVP_ENCODE_CTX_free(ctx);
-    pem_free(name, flags);
+    pem_free(name, flags, 0);
     BIO_free(headerB);
     BIO_free(dataB);
     return ret;