Properly zero cipher_data for ChaCha20-Poly1305 on cleanup
[openssl.git] / crypto / buffer / buffer.c
1 /*
2  * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <stdio.h>
11 #include "internal/cryptlib.h"
12 #include <openssl/buffer.h>
13
14 /*
15  * LIMIT_BEFORE_EXPANSION is the maximum n such that (n+3)/3*4 < 2**31. That
16  * function is applied in several functions in this file and this limit
17  * ensures that the result fits in an int.
18  */
19 #define LIMIT_BEFORE_EXPANSION 0x5ffffffc
20
21 BUF_MEM *BUF_MEM_new_ex(unsigned long flags)
22 {
23     BUF_MEM *ret;
24
25     ret = BUF_MEM_new();
26     if (ret != NULL)
27         ret->flags = flags;
28     return (ret);
29 }
30
31 BUF_MEM *BUF_MEM_new(void)
32 {
33     BUF_MEM *ret;
34
35     ret = OPENSSL_zalloc(sizeof(*ret));
36     if (ret == NULL) {
37         BUFerr(BUF_F_BUF_MEM_NEW, ERR_R_MALLOC_FAILURE);
38         return (NULL);
39     }
40     return (ret);
41 }
42
43 void BUF_MEM_free(BUF_MEM *a)
44 {
45     if (a == NULL)
46         return;
47
48     if (a->data != NULL) {
49         if (a->flags & BUF_MEM_FLAG_SECURE)
50             OPENSSL_secure_free(a->data);
51         else
52             OPENSSL_clear_free(a->data, a->max);
53     }
54     OPENSSL_free(a);
55 }
56
57 /* Allocate a block of secure memory; copy over old data if there
58  * was any, and then free it. */
59 static char *sec_alloc_realloc(BUF_MEM *str, size_t len)
60 {
61     char *ret;
62
63     ret = OPENSSL_secure_malloc(len);
64     if (str->data != NULL) {
65         if (ret != NULL)
66             memcpy(ret, str->data, str->length);
67         OPENSSL_secure_free(str->data);
68     }
69     return (ret);
70 }
71
72 size_t BUF_MEM_grow(BUF_MEM *str, size_t len)
73 {
74     char *ret;
75     size_t n;
76
77     if (str->length >= len) {
78         str->length = len;
79         return (len);
80     }
81     if (str->max >= len) {
82         if (str->data != NULL)
83             memset(&str->data[str->length], 0, len - str->length);
84         str->length = len;
85         return (len);
86     }
87     /* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
88     if (len > LIMIT_BEFORE_EXPANSION) {
89         BUFerr(BUF_F_BUF_MEM_GROW, ERR_R_MALLOC_FAILURE);
90         return 0;
91     }
92     n = (len + 3) / 3 * 4;
93     if ((str->flags & BUF_MEM_FLAG_SECURE))
94         ret = sec_alloc_realloc(str, n);
95     else
96         ret = OPENSSL_realloc(str->data, n);
97     if (ret == NULL) {
98         BUFerr(BUF_F_BUF_MEM_GROW, ERR_R_MALLOC_FAILURE);
99         len = 0;
100     } else {
101         str->data = ret;
102         str->max = n;
103         memset(&str->data[str->length], 0, len - str->length);
104         str->length = len;
105     }
106     return (len);
107 }
108
109 size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len)
110 {
111     char *ret;
112     size_t n;
113
114     if (str->length >= len) {
115         if (str->data != NULL)
116             memset(&str->data[len], 0, str->length - len);
117         str->length = len;
118         return (len);
119     }
120     if (str->max >= len) {
121         memset(&str->data[str->length], 0, len - str->length);
122         str->length = len;
123         return (len);
124     }
125     /* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
126     if (len > LIMIT_BEFORE_EXPANSION) {
127         BUFerr(BUF_F_BUF_MEM_GROW_CLEAN, ERR_R_MALLOC_FAILURE);
128         return 0;
129     }
130     n = (len + 3) / 3 * 4;
131     if ((str->flags & BUF_MEM_FLAG_SECURE))
132         ret = sec_alloc_realloc(str, n);
133     else
134         ret = OPENSSL_clear_realloc(str->data, str->max, n);
135     if (ret == NULL) {
136         BUFerr(BUF_F_BUF_MEM_GROW_CLEAN, ERR_R_MALLOC_FAILURE);
137         len = 0;
138     } else {
139         str->data = ret;
140         str->max = n;
141         memset(&str->data[str->length], 0, len - str->length);
142         str->length = len;
143     }
144     return (len);
145 }
146
147 void BUF_reverse(unsigned char *out, const unsigned char *in, size_t size)
148 {
149     size_t i;
150     if (in) {
151         out += size - 1;
152         for (i = 0; i < size; i++)
153             *out-- = *in++;
154     } else {
155         unsigned char *q;
156         char c;
157         q = out + size - 1;
158         for (i = 0; i < size / 2; i++) {
159             c = *q;
160             *q-- = *out;
161             *out++ = c;
162         }
163     }
164 }