1/*
2 * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (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
21BUF_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
31BUF_MEM *BUF_MEM_new(void)
32{
33    BUF_MEM *ret;
34
35    ret = OPENSSL_zalloc(sizeof(*ret));
36    if (ret == NULL) {
37        ERR_raise(ERR_LIB_BUF, ERR_R_MALLOC_FAILURE);
38        return NULL;
39    }
40    return ret;
41}
42
43void BUF_MEM_free(BUF_MEM *a)
44{
45    if (a == NULL)
46        return;
47    if (a->data != NULL) {
48        if (a->flags & BUF_MEM_FLAG_SECURE)
49            OPENSSL_secure_clear_free(a->data, a->max);
50        else
51            OPENSSL_clear_free(a->data, a->max);
52    }
53    OPENSSL_free(a);
54}
55
56/* Allocate a block of secure memory; copy over old data if there
57 * was any, and then free it. */
58static char *sec_alloc_realloc(BUF_MEM *str, size_t len)
59{
60    char *ret;
61
62    ret = OPENSSL_secure_malloc(len);
63    if (str->data != NULL) {
64        if (ret != NULL) {
65            memcpy(ret, str->data, str->length);
66            OPENSSL_secure_clear_free(str->data, str->length);
67            str->data = NULL;
68        }
69    }
70    return ret;
71}
72
73size_t BUF_MEM_grow(BUF_MEM *str, size_t len)
74{
75    char *ret;
76    size_t n;
77
78    if (str->length >= len) {
79        str->length = len;
80        return len;
81    }
82    if (str->max >= len) {
83        if (str->data != NULL)
84            memset(&str->data[str->length], 0, len - str->length);
85        str->length = len;
86        return len;
87    }
88    /* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
89    if (len > LIMIT_BEFORE_EXPANSION) {
90        ERR_raise(ERR_LIB_BUF, ERR_R_MALLOC_FAILURE);
91        return 0;
92    }
93    n = (len + 3) / 3 * 4;
94    if ((str->flags & BUF_MEM_FLAG_SECURE))
95        ret = sec_alloc_realloc(str, n);
96    else
97        ret = OPENSSL_realloc(str->data, n);
98    if (ret == NULL) {
99        ERR_raise(ERR_LIB_BUF, ERR_R_MALLOC_FAILURE);
100        len = 0;
101    } else {
102        str->data = ret;
103        str->max = n;
104        memset(&str->data[str->length], 0, len - str->length);
105        str->length = len;
106    }
107    return len;
108}
109
110size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len)
111{
112    char *ret;
113    size_t n;
114
115    if (str->length >= len) {
116        if (str->data != NULL)
117            memset(&str->data[len], 0, str->length - len);
118        str->length = len;
119        return len;
120    }
121    if (str->max >= len) {
122        memset(&str->data[str->length], 0, len - str->length);
123        str->length = len;
124        return len;
125    }
126    /* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
127    if (len > LIMIT_BEFORE_EXPANSION) {
128        ERR_raise(ERR_LIB_BUF, ERR_R_MALLOC_FAILURE);
129        return 0;
130    }
131    n = (len + 3) / 3 * 4;
132    if ((str->flags & BUF_MEM_FLAG_SECURE))
133        ret = sec_alloc_realloc(str, n);
134    else
135        ret = OPENSSL_clear_realloc(str->data, str->max, n);
136    if (ret == NULL) {
137        ERR_raise(ERR_LIB_BUF, ERR_R_MALLOC_FAILURE);
138        len = 0;
139    } else {
140        str->data = ret;
141        str->max = n;
142        memset(&str->data[str->length], 0, len - str->length);
143        str->length = len;
144    }
145    return len;
146}
147
148void BUF_reverse(unsigned char *out, const unsigned char *in, size_t size)
149{
150    size_t i;
151    if (in) {
152        out += size - 1;
153        for (i = 0; i < size; i++)
154            *out-- = *in++;
155    } else {
156        unsigned char *q;
157        char c;
158        q = out + size - 1;
159        for (i = 0; i < size / 2; i++) {
160            c = *q;
161            *q-- = *out;
162            *out++ = c;
163        }
164    }
165}
166