/src/openssl/crypto/comp/c_zstd.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright 1998-2023 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  |  |  * Uses zstd compression library from https://github.com/facebook/zstd  | 
10  |  |  * Requires version 1.4.x (latest as of this writing is 1.4.5)  | 
11  |  |  * Using custom free functions require static linking, so that is disabled when  | 
12  |  |  * using the shared library.  | 
13  |  |  */  | 
14  |  |  | 
15  |  | #include <stdio.h>  | 
16  |  | #include <stdlib.h>  | 
17  |  | #include <string.h>  | 
18  |  | #include <openssl/objects.h>  | 
19  |  | #include "internal/comp.h"  | 
20  |  | #include <openssl/err.h>  | 
21  |  | #include "crypto/cryptlib.h"  | 
22  |  | #include "internal/bio.h"  | 
23  |  | #include "internal/thread_once.h"  | 
24  |  | #include "comp_local.h"  | 
25  |  |  | 
26  |  | COMP_METHOD *COMP_zstd(void);  | 
27  |  |  | 
28  |  | #ifdef OPENSSL_NO_ZSTD  | 
29  |  | # undef ZSTD_SHARED  | 
30  |  | #else  | 
31  |  |  | 
32  |  | # ifndef ZSTD_SHARED  | 
33  |  | #  define ZSTD_STATIC_LINKING_ONLY  | 
34  |  | # endif  | 
35  |  | # include <zstd.h>  | 
36  |  |  | 
37  |  | /* Note: There is also a linux zstd.h file in the kernel source */  | 
38  |  | # ifndef ZSTD_H_235446  | 
39  |  | #  error Wrong (i.e. linux) zstd.h included.  | 
40  |  | # endif  | 
41  |  |  | 
42  |  | # if ZSTD_VERSION_MAJOR != 1 && ZSTD_VERSION_MINOR < 4  | 
43  |  | #  error Expecting version 1.4 or greater of ZSTD  | 
44  |  | # endif  | 
45  |  |  | 
46  |  | # ifndef ZSTD_SHARED  | 
47  |  | /* memory allocations functions for zstd initialisation */  | 
48  |  | static void *zstd_alloc(void *opaque, size_t size)  | 
49  |  | { | 
50  |  |     return OPENSSL_zalloc(size);  | 
51  |  | }  | 
52  |  |  | 
53  |  | static void zstd_free(void *opaque, void *address)  | 
54  |  | { | 
55  |  |     OPENSSL_free(address);  | 
56  |  | }  | 
57  |  |  | 
58  |  | static ZSTD_customMem zstd_mem_funcs = { | 
59  |  |     zstd_alloc,  | 
60  |  |     zstd_free,  | 
61  |  |     NULL  | 
62  |  | };  | 
63  |  | # endif  | 
64  |  |  | 
65  |  | /*  | 
66  |  |  * When OpenSSL is built on Windows, we do not want to require that  | 
67  |  |  * the LIBZSTD.DLL be available in order for the OpenSSL DLLs to  | 
68  |  |  * work.  Therefore, all ZSTD routines are loaded at run time  | 
69  |  |  * and we do not link to a .LIB file when ZSTD_SHARED is set.  | 
70  |  |  */  | 
71  |  | # if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)  | 
72  |  | #  include <windows.h>  | 
73  |  | # endif  | 
74  |  |  | 
75  |  | # ifdef ZSTD_SHARED  | 
76  |  | #  include "internal/dso.h"  | 
77  |  |  | 
78  |  | /* Function pointers */  | 
79  |  | typedef ZSTD_CStream* (*createCStream_ft)(void);  | 
80  |  | typedef size_t (*initCStream_ft)(ZSTD_CStream*, int);  | 
81  |  | typedef size_t (*freeCStream_ft)(ZSTD_CStream*);  | 
82  |  | typedef size_t (*compressStream2_ft)(ZSTD_CCtx*, ZSTD_outBuffer*, ZSTD_inBuffer*, ZSTD_EndDirective);  | 
83  |  | typedef size_t (*flushStream_ft)(ZSTD_CStream*, ZSTD_outBuffer*);  | 
84  |  | typedef size_t (*endStream_ft)(ZSTD_CStream*, ZSTD_outBuffer*);  | 
85  |  | typedef size_t (*compress_ft)(void*, size_t, const void*, size_t, int);  | 
86  |  | typedef ZSTD_DStream* (*createDStream_ft)(void);  | 
87  |  | typedef size_t (*initDStream_ft)(ZSTD_DStream*);  | 
88  |  | typedef size_t (*freeDStream_ft)(ZSTD_DStream*);  | 
89  |  | typedef size_t (*decompressStream_ft)(ZSTD_DStream*, ZSTD_outBuffer*, ZSTD_inBuffer*);  | 
90  |  | typedef size_t (*decompress_ft)(void*, size_t, const void*, size_t);  | 
91  |  | typedef unsigned (*isError_ft)(size_t);  | 
92  |  | typedef const char* (*getErrorName_ft)(size_t);  | 
93  |  | typedef size_t (*DStreamInSize_ft)(void);  | 
94  |  | typedef size_t (*CStreamInSize_ft)(void);  | 
95  |  |  | 
96  |  | static createCStream_ft p_createCStream = NULL;  | 
97  |  | static initCStream_ft p_initCStream = NULL;  | 
98  |  | static freeCStream_ft p_freeCStream = NULL;  | 
99  |  | static compressStream2_ft p_compressStream2 = NULL;  | 
100  |  | static flushStream_ft p_flushStream = NULL;  | 
101  |  | static endStream_ft p_endStream = NULL;  | 
102  |  | static compress_ft p_compress = NULL;  | 
103  |  | static createDStream_ft p_createDStream = NULL;  | 
104  |  | static initDStream_ft p_initDStream = NULL;  | 
105  |  | static freeDStream_ft p_freeDStream = NULL;  | 
106  |  | static decompressStream_ft p_decompressStream = NULL;  | 
107  |  | static decompress_ft p_decompress = NULL;  | 
108  |  | static isError_ft p_isError = NULL;  | 
109  |  | static getErrorName_ft p_getErrorName = NULL;  | 
110  |  | static DStreamInSize_ft p_DStreamInSize = NULL;  | 
111  |  | static CStreamInSize_ft p_CStreamInSize = NULL;  | 
112  |  |  | 
113  |  | static DSO *zstd_dso = NULL;  | 
114  |  |  | 
115  |  | #  define ZSTD_createCStream p_createCStream  | 
116  |  | #  define ZSTD_initCStream p_initCStream  | 
117  |  | #  define ZSTD_freeCStream p_freeCStream  | 
118  |  | #  define ZSTD_compressStream2 p_compressStream2  | 
119  |  | #  define ZSTD_flushStream p_flushStream  | 
120  |  | #  define ZSTD_endStream p_endStream  | 
121  |  | #  define ZSTD_compress p_compress  | 
122  |  | #  define ZSTD_createDStream p_createDStream  | 
123  |  | #  define ZSTD_initDStream p_initDStream  | 
124  |  | #  define ZSTD_freeDStream p_freeDStream  | 
125  |  | #  define ZSTD_decompressStream p_decompressStream  | 
126  |  | #  define ZSTD_decompress p_decompress  | 
127  |  | #  define ZSTD_isError p_isError  | 
128  |  | #  define ZSTD_getErrorName p_getErrorName  | 
129  |  | #  define ZSTD_DStreamInSize p_DStreamInSize  | 
130  |  | #  define ZSTD_CStreamInSize p_CStreamInSize  | 
131  |  |  | 
132  |  | # endif /* ifdef ZSTD_SHARED */  | 
133  |  |  | 
134  |  | struct zstd_state { | 
135  |  |     ZSTD_CStream *compressor;  | 
136  |  |     ZSTD_DStream *decompressor;  | 
137  |  | };  | 
138  |  |  | 
139  |  | static int zstd_stateful_init(COMP_CTX *ctx)  | 
140  |  | { | 
141  |  |     struct zstd_state *state = OPENSSL_zalloc(sizeof(*state));  | 
142  |  |  | 
143  |  |     if (state == NULL)  | 
144  |  |         return 0;  | 
145  |  |  | 
146  |  | # ifdef ZSTD_SHARED  | 
147  |  |     state->compressor = ZSTD_createCStream();  | 
148  |  | # else  | 
149  |  |     state->compressor = ZSTD_createCStream_advanced(zstd_mem_funcs);  | 
150  |  | # endif  | 
151  |  |     if (state->compressor == NULL)  | 
152  |  |         goto err;  | 
153  |  |     ZSTD_initCStream(state->compressor, ZSTD_CLEVEL_DEFAULT);  | 
154  |  |  | 
155  |  | # ifdef ZSTD_SHARED  | 
156  |  |     state->decompressor = ZSTD_createDStream();  | 
157  |  | # else  | 
158  |  |     state->decompressor = ZSTD_createDStream_advanced(zstd_mem_funcs);  | 
159  |  | # endif  | 
160  |  |     if (state->decompressor == NULL)  | 
161  |  |         goto err;  | 
162  |  |     ZSTD_initDStream(state->decompressor);  | 
163  |  |  | 
164  |  |     ctx->data = state;  | 
165  |  |     return 1;  | 
166  |  |  err:  | 
167  |  |     ZSTD_freeCStream(state->compressor);  | 
168  |  |     ZSTD_freeDStream(state->decompressor);  | 
169  |  |     OPENSSL_free(state);  | 
170  |  |     return 0;  | 
171  |  | }  | 
172  |  |  | 
173  |  | static void zstd_stateful_finish(COMP_CTX *ctx)  | 
174  |  | { | 
175  |  |     struct zstd_state *state = ctx->data;  | 
176  |  |  | 
177  |  |     if (state != NULL) { | 
178  |  |         ZSTD_freeCStream(state->compressor);  | 
179  |  |         ZSTD_freeDStream(state->decompressor);  | 
180  |  |         OPENSSL_free(state);  | 
181  |  |         ctx->data = NULL;  | 
182  |  |     }  | 
183  |  | }  | 
184  |  |  | 
185  |  | static ossl_ssize_t zstd_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,  | 
186  |  |                                                  size_t olen, unsigned char *in,  | 
187  |  |                                                  size_t ilen)  | 
188  |  | { | 
189  |  |     ZSTD_inBuffer inbuf;  | 
190  |  |     ZSTD_outBuffer outbuf;  | 
191  |  |     size_t ret;  | 
192  |  |     ossl_ssize_t fret;  | 
193  |  |     struct zstd_state *state = ctx->data;  | 
194  |  |  | 
195  |  |     inbuf.src = in;  | 
196  |  |     inbuf.size = ilen;  | 
197  |  |     inbuf.pos = 0;  | 
198  |  |     outbuf.dst = out;  | 
199  |  |     outbuf.size = olen;  | 
200  |  |     outbuf.pos = 0;  | 
201  |  |  | 
202  |  |     if (state == NULL)  | 
203  |  |         return -1;  | 
204  |  |  | 
205  |  |     /* If input length is zero, end the stream/frame ? */  | 
206  |  |     if (ilen == 0) { | 
207  |  |         ret = ZSTD_endStream(state->compressor, &outbuf);  | 
208  |  |         if (ZSTD_isError(ret))  | 
209  |  |             return -1;  | 
210  |  |         goto end;  | 
211  |  |     }  | 
212  |  |  | 
213  |  |     /*  | 
214  |  |      * The finish API does not provide a final output buffer,  | 
215  |  |      * so each compress operation has to be ended, if all  | 
216  |  |      * the input data can't be accepted, or there is more output,  | 
217  |  |      * this has to be considered an error, since there is no more  | 
218  |  |      * output buffer space.  | 
219  |  |      */  | 
220  |  |     do { | 
221  |  |         ret = ZSTD_compressStream2(state->compressor, &outbuf, &inbuf, ZSTD_e_continue);  | 
222  |  |         if (ZSTD_isError(ret))  | 
223  |  |             return -1;  | 
224  |  |         /* do I need to check for ret == 0 ? */  | 
225  |  |     } while (inbuf.pos < inbuf.size);  | 
226  |  |  | 
227  |  |     /* Did not consume all the data */  | 
228  |  |     if (inbuf.pos < inbuf.size)  | 
229  |  |         return -1;  | 
230  |  |  | 
231  |  |     ret = ZSTD_flushStream(state->compressor, &outbuf);  | 
232  |  |     if (ZSTD_isError(ret))  | 
233  |  |         return -1;  | 
234  |  |  | 
235  |  |  end:  | 
236  |  |     if (outbuf.pos > OSSL_SSIZE_MAX)  | 
237  |  |         return -1;  | 
238  |  |     fret = (ossl_ssize_t)outbuf.pos;  | 
239  |  |     if (fret < 0)  | 
240  |  |         return -1;  | 
241  |  |     return fret;  | 
242  |  | }  | 
243  |  |  | 
244  |  | static ossl_ssize_t zstd_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,  | 
245  |  |                                                size_t olen, unsigned char *in,  | 
246  |  |                                                size_t ilen)  | 
247  |  | { | 
248  |  |     ZSTD_inBuffer inbuf;  | 
249  |  |     ZSTD_outBuffer outbuf;  | 
250  |  |     size_t ret;  | 
251  |  |     ossl_ssize_t fret;  | 
252  |  |     struct zstd_state *state = ctx->data;  | 
253  |  |  | 
254  |  |     inbuf.src = in;  | 
255  |  |     inbuf.size = ilen;  | 
256  |  |     inbuf.pos = 0;  | 
257  |  |     outbuf.dst = out;  | 
258  |  |     outbuf.size = olen;  | 
259  |  |     outbuf.pos = 0;  | 
260  |  |  | 
261  |  |     if (state == NULL)  | 
262  |  |         return -1;  | 
263  |  |  | 
264  |  |     if (ilen == 0)  | 
265  |  |         return 0;  | 
266  |  |  | 
267  |  |     do { | 
268  |  |         ret = ZSTD_decompressStream(state->decompressor, &outbuf, &inbuf);  | 
269  |  |         if (ZSTD_isError(ret))  | 
270  |  |             return -1;  | 
271  |  |         /* If we completed a frame, and there's more data, try again */  | 
272  |  |     } while (ret == 0 && inbuf.pos < inbuf.size);  | 
273  |  |  | 
274  |  |     /* Did not consume all the data */  | 
275  |  |     if (inbuf.pos < inbuf.size)  | 
276  |  |         return -1;  | 
277  |  |  | 
278  |  |     if (outbuf.pos > OSSL_SSIZE_MAX)  | 
279  |  |         return -1;  | 
280  |  |     fret = (ossl_ssize_t)outbuf.pos;  | 
281  |  |     if (fret < 0)  | 
282  |  |         return -1;  | 
283  |  |     return fret;  | 
284  |  | }  | 
285  |  |  | 
286  |  |  | 
287  |  | static COMP_METHOD zstd_stateful_method = { | 
288  |  |     NID_zstd,  | 
289  |  |     LN_zstd,  | 
290  |  |     zstd_stateful_init,  | 
291  |  |     zstd_stateful_finish,  | 
292  |  |     zstd_stateful_compress_block,  | 
293  |  |     zstd_stateful_expand_block  | 
294  |  | };  | 
295  |  |  | 
296  |  | static int zstd_oneshot_init(COMP_CTX *ctx)  | 
297  |  | { | 
298  |  |     return 1;  | 
299  |  | }  | 
300  |  |  | 
301  |  | static void zstd_oneshot_finish(COMP_CTX *ctx)  | 
302  |  | { | 
303  |  | }  | 
304  |  |  | 
305  |  | static ossl_ssize_t zstd_oneshot_compress_block(COMP_CTX *ctx, unsigned char *out,  | 
306  |  |                                                size_t olen, unsigned char *in,  | 
307  |  |                                                size_t ilen)  | 
308  |  | { | 
309  |  |     size_t out_size;  | 
310  |  |     ossl_ssize_t ret;  | 
311  |  |  | 
312  |  |     if (ilen == 0)  | 
313  |  |         return 0;  | 
314  |  |  | 
315  |  |     /* Note: uses STDLIB memory allocators */  | 
316  |  |     out_size = ZSTD_compress(out, olen, in, ilen, ZSTD_CLEVEL_DEFAULT);  | 
317  |  |     if (ZSTD_isError(out_size))  | 
318  |  |         return -1;  | 
319  |  |  | 
320  |  |     if (out_size > OSSL_SSIZE_MAX)  | 
321  |  |         return -1;  | 
322  |  |     ret = (ossl_ssize_t)out_size;  | 
323  |  |     if (ret < 0)  | 
324  |  |         return -1;  | 
325  |  |     return ret;  | 
326  |  | }  | 
327  |  |  | 
328  |  | static ossl_ssize_t zstd_oneshot_expand_block(COMP_CTX *ctx, unsigned char *out,  | 
329  |  |                                               size_t olen, unsigned char *in,  | 
330  |  |                                               size_t ilen)  | 
331  |  | { | 
332  |  |     size_t out_size;  | 
333  |  |     ossl_ssize_t ret;  | 
334  |  |  | 
335  |  |     if (ilen == 0)  | 
336  |  |         return 0;  | 
337  |  |  | 
338  |  |     /* Note: uses STDLIB memory allocators */  | 
339  |  |     out_size = ZSTD_decompress(out, olen, in, ilen);  | 
340  |  |     if (ZSTD_isError(out_size))  | 
341  |  |         return -1;  | 
342  |  |  | 
343  |  |     if (out_size > OSSL_SSIZE_MAX)  | 
344  |  |         return -1;  | 
345  |  |     ret = (ossl_ssize_t)out_size;  | 
346  |  |     if (ret < 0)  | 
347  |  |         return -1;  | 
348  |  |     return ret;  | 
349  |  | }  | 
350  |  |  | 
351  |  | static COMP_METHOD zstd_oneshot_method = { | 
352  |  |     NID_zstd,  | 
353  |  |     LN_zstd,  | 
354  |  |     zstd_oneshot_init,  | 
355  |  |     zstd_oneshot_finish,  | 
356  |  |     zstd_oneshot_compress_block,  | 
357  |  |     zstd_oneshot_expand_block  | 
358  |  | };  | 
359  |  |  | 
360  |  | static CRYPTO_ONCE zstd_once = CRYPTO_ONCE_STATIC_INIT;  | 
361  |  | DEFINE_RUN_ONCE_STATIC(ossl_comp_zstd_init)  | 
362  |  | { | 
363  |  | # ifdef ZSTD_SHARED  | 
364  |  | #  if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)  | 
365  |  | #   define LIBZSTD "LIBZSTD"  | 
366  |  | #  else  | 
367  |  | #   define LIBZSTD  "zstd"  | 
368  |  | #  endif  | 
369  |  |  | 
370  |  |     zstd_dso = DSO_load(NULL, LIBZSTD, NULL, 0);  | 
371  |  |     if (zstd_dso != NULL) { | 
372  |  |         p_createCStream = (createCStream_ft)DSO_bind_func(zstd_dso, "ZSTD_createCStream");  | 
373  |  |         p_initCStream = (initCStream_ft)DSO_bind_func(zstd_dso, "ZSTD_initCStream");  | 
374  |  |         p_freeCStream = (freeCStream_ft)DSO_bind_func(zstd_dso, "ZSTD_freeCStream");  | 
375  |  |         p_compressStream2 = (compressStream2_ft)DSO_bind_func(zstd_dso, "ZSTD_compressStream2");  | 
376  |  |         p_flushStream = (flushStream_ft)DSO_bind_func(zstd_dso, "ZSTD_flushStream");  | 
377  |  |         p_endStream = (endStream_ft)DSO_bind_func(zstd_dso, "ZSTD_endStream");  | 
378  |  |         p_compress = (compress_ft)DSO_bind_func(zstd_dso, "ZSTD_compress");  | 
379  |  |         p_createDStream = (createDStream_ft)DSO_bind_func(zstd_dso, "ZSTD_createDStream");  | 
380  |  |         p_initDStream = (initDStream_ft)DSO_bind_func(zstd_dso, "ZSTD_initDStream");  | 
381  |  |         p_freeDStream = (freeDStream_ft)DSO_bind_func(zstd_dso, "ZSTD_freeDStream");  | 
382  |  |         p_decompressStream = (decompressStream_ft)DSO_bind_func(zstd_dso, "ZSTD_decompressStream");  | 
383  |  |         p_decompress = (decompress_ft)DSO_bind_func(zstd_dso, "ZSTD_decompress");  | 
384  |  |         p_isError = (isError_ft)DSO_bind_func(zstd_dso, "ZSTD_isError");  | 
385  |  |         p_getErrorName = (getErrorName_ft)DSO_bind_func(zstd_dso, "ZSTD_getErrorName");  | 
386  |  |         p_DStreamInSize = (DStreamInSize_ft)DSO_bind_func(zstd_dso, "ZSTD_DStreamInSize");  | 
387  |  |         p_CStreamInSize = (CStreamInSize_ft)DSO_bind_func(zstd_dso, "ZSTD_CStreamInSize");  | 
388  |  |     }  | 
389  |  |  | 
390  |  |     if (p_createCStream == NULL || p_initCStream == NULL || p_freeCStream == NULL  | 
391  |  |             || p_compressStream2 == NULL || p_flushStream == NULL || p_endStream == NULL  | 
392  |  |             || p_compress == NULL || p_createDStream == NULL || p_initDStream == NULL  | 
393  |  |             || p_freeDStream == NULL || p_decompressStream == NULL || p_decompress == NULL  | 
394  |  |             || p_isError == NULL || p_getErrorName == NULL || p_DStreamInSize == NULL  | 
395  |  |             || p_CStreamInSize == NULL) { | 
396  |  |         ossl_comp_zstd_cleanup();  | 
397  |  |         return 0;  | 
398  |  |     }  | 
399  |  | # endif  | 
400  |  |     return 1;  | 
401  |  | }  | 
402  |  | #endif /* ifndef ZSTD / else */  | 
403  |  |  | 
404  |  | COMP_METHOD *COMP_zstd(void)  | 
405  | 0  | { | 
406  | 0  |     COMP_METHOD *meth = NULL;  | 
407  |  | 
  | 
408  |  | #ifndef OPENSSL_NO_ZSTD  | 
409  |  |     if (RUN_ONCE(&zstd_once, ossl_comp_zstd_init))  | 
410  |  |         meth = &zstd_stateful_method;  | 
411  |  | #endif  | 
412  | 0  |     return meth;  | 
413  | 0  | }  | 
414  |  |  | 
415  |  | COMP_METHOD *COMP_zstd_oneshot(void)  | 
416  | 0  | { | 
417  | 0  |     COMP_METHOD *meth = NULL;  | 
418  |  | 
  | 
419  |  | #ifndef OPENSSL_NO_ZSTD  | 
420  |  |     if (RUN_ONCE(&zstd_once, ossl_comp_zstd_init))  | 
421  |  |         meth = &zstd_oneshot_method;  | 
422  |  | #endif  | 
423  | 0  |     return meth;  | 
424  | 0  | }  | 
425  |  |  | 
426  |  | /* Also called from OPENSSL_cleanup() */  | 
427  |  | void ossl_comp_zstd_cleanup(void)  | 
428  | 1  | { | 
429  |  | #ifdef ZSTD_SHARED  | 
430  |  |     DSO_free(zstd_dso);  | 
431  |  |     zstd_dso = NULL;  | 
432  |  |     p_createCStream = NULL;  | 
433  |  |     p_initCStream = NULL;  | 
434  |  |     p_freeCStream = NULL;  | 
435  |  |     p_compressStream2 = NULL;  | 
436  |  |     p_flushStream = NULL;  | 
437  |  |     p_endStream = NULL;  | 
438  |  |     p_compress = NULL;  | 
439  |  |     p_createDStream = NULL;  | 
440  |  |     p_initDStream = NULL;  | 
441  |  |     p_freeDStream = NULL;  | 
442  |  |     p_decompressStream = NULL;  | 
443  |  |     p_decompress = NULL;  | 
444  |  |     p_isError = NULL;  | 
445  |  |     p_getErrorName = NULL;  | 
446  |  |     p_DStreamInSize = NULL;  | 
447  |  |     p_CStreamInSize = NULL;  | 
448  |  | #endif  | 
449  | 1  | }  | 
450  |  |  | 
451  |  | #ifndef OPENSSL_NO_ZSTD  | 
452  |  |  | 
453  |  | /* Zstd-based compression/decompression filter BIO */  | 
454  |  |  | 
455  |  | typedef struct { | 
456  |  |     struct { /* input structure */ | 
457  |  |         ZSTD_DStream *state;  | 
458  |  |         ZSTD_inBuffer inbuf; /* has const src */  | 
459  |  |         size_t bufsize;  | 
460  |  |         void* buffer;  | 
461  |  |     } decompress;  | 
462  |  |     struct { /* output structure */ | 
463  |  |         ZSTD_CStream *state;  | 
464  |  |         ZSTD_outBuffer outbuf;  | 
465  |  |         size_t bufsize;  | 
466  |  |         size_t write_pos;  | 
467  |  |     } compress;  | 
468  |  | } BIO_ZSTD_CTX;  | 
469  |  |  | 
470  |  | # define ZSTD_DEFAULT_BUFSIZE 1024  | 
471  |  |  | 
472  |  | static int bio_zstd_new(BIO *bi);  | 
473  |  | static int bio_zstd_free(BIO *bi);  | 
474  |  | static int bio_zstd_read(BIO *b, char *out, int outl);  | 
475  |  | static int bio_zstd_write(BIO *b, const char *in, int inl);  | 
476  |  | static long bio_zstd_ctrl(BIO *b, int cmd, long num, void *ptr);  | 
477  |  | static long bio_zstd_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);  | 
478  |  |  | 
479  |  | static const BIO_METHOD bio_meth_zstd = { | 
480  |  |     BIO_TYPE_COMP,  | 
481  |  |     "zstd",  | 
482  |  |     /* TODO: Convert to new style write function */  | 
483  |  |     bwrite_conv,  | 
484  |  |     bio_zstd_write,  | 
485  |  |     /* TODO: Convert to new style read function */  | 
486  |  |     bread_conv,  | 
487  |  |     bio_zstd_read,  | 
488  |  |     NULL,                      /* bio_zstd_puts, */  | 
489  |  |     NULL,                      /* bio_zstd_gets, */  | 
490  |  |     bio_zstd_ctrl,  | 
491  |  |     bio_zstd_new,  | 
492  |  |     bio_zstd_free,  | 
493  |  |     bio_zstd_callback_ctrl  | 
494  |  | };  | 
495  |  | #endif  | 
496  |  |  | 
497  |  | const BIO_METHOD *BIO_f_zstd(void)  | 
498  | 0  | { | 
499  |  | #ifndef OPENSSL_NO_ZSTD  | 
500  |  |     if (RUN_ONCE(&zstd_once, ossl_comp_zstd_init))  | 
501  |  |         return &bio_meth_zstd;  | 
502  |  | #endif  | 
503  | 0  |     return NULL;  | 
504  | 0  | }  | 
505  |  |  | 
506  |  | #ifndef OPENSSL_NO_ZSTD  | 
507  |  | static int bio_zstd_new(BIO *bi)  | 
508  |  | { | 
509  |  |     BIO_ZSTD_CTX *ctx;  | 
510  |  |  | 
511  |  | # ifdef ZSTD_SHARED  | 
512  |  |     (void)COMP_zstd();  | 
513  |  |     if (zstd_dso == NULL) { | 
514  |  |         ERR_raise(ERR_LIB_COMP, COMP_R_ZSTD_NOT_SUPPORTED);  | 
515  |  |         return 0;  | 
516  |  |     }  | 
517  |  | # endif  | 
518  |  |     ctx = OPENSSL_zalloc(sizeof(*ctx));  | 
519  |  |     if (ctx == NULL) { | 
520  |  |         ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);  | 
521  |  |         return 0;  | 
522  |  |     }  | 
523  |  |  | 
524  |  | # ifdef ZSTD_SHARED  | 
525  |  |     ctx->decompress.state =  ZSTD_createDStream();  | 
526  |  | # else  | 
527  |  |     ctx->decompress.state =  ZSTD_createDStream_advanced(zstd_mem_funcs);  | 
528  |  | # endif  | 
529  |  |     if (ctx->decompress.state == NULL)  | 
530  |  |         goto err;  | 
531  |  |     ZSTD_initDStream(ctx->decompress.state);  | 
532  |  |     ctx->decompress.bufsize = ZSTD_DStreamInSize();  | 
533  |  |  | 
534  |  | # ifdef ZSTD_SHARED  | 
535  |  |     ctx->compress.state = ZSTD_createCStream();  | 
536  |  | # else  | 
537  |  |     ctx->compress.state = ZSTD_createCStream_advanced(zstd_mem_funcs);  | 
538  |  | # endif  | 
539  |  |     if (ctx->compress.state == NULL)  | 
540  |  |         goto err;  | 
541  |  |     ZSTD_initCStream(ctx->compress.state, ZSTD_CLEVEL_DEFAULT);  | 
542  |  |     ctx->compress.bufsize = ZSTD_CStreamInSize();  | 
543  |  |  | 
544  |  |     BIO_set_init(bi, 1);  | 
545  |  |     BIO_set_data(bi, ctx);  | 
546  |  |  | 
547  |  |     return 1;  | 
548  |  |  err:  | 
549  |  |     ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);  | 
550  |  |     ZSTD_freeDStream(ctx->decompress.state);  | 
551  |  |     ZSTD_freeCStream(ctx->compress.state);  | 
552  |  |     OPENSSL_free(ctx);  | 
553  |  |     return 0;  | 
554  |  | }  | 
555  |  |  | 
556  |  | static int bio_zstd_free(BIO *bi)  | 
557  |  | { | 
558  |  |     BIO_ZSTD_CTX *ctx;  | 
559  |  |  | 
560  |  |     if (bi == NULL)  | 
561  |  |         return 0;  | 
562  |  |  | 
563  |  |     ctx = BIO_get_data(bi);  | 
564  |  |     if (ctx != NULL) { | 
565  |  |         ZSTD_freeDStream(ctx->decompress.state);  | 
566  |  |         OPENSSL_free(ctx->decompress.buffer);  | 
567  |  |         ZSTD_freeCStream(ctx->compress.state);  | 
568  |  |         OPENSSL_free(ctx->compress.outbuf.dst);  | 
569  |  |         OPENSSL_free(ctx);  | 
570  |  |     }  | 
571  |  |     BIO_set_data(bi, NULL);  | 
572  |  |     BIO_set_init(bi, 0);  | 
573  |  |  | 
574  |  |     return 1;  | 
575  |  | }  | 
576  |  |  | 
577  |  | static int bio_zstd_read(BIO *b, char *out, int outl)  | 
578  |  | { | 
579  |  |     BIO_ZSTD_CTX *ctx;  | 
580  |  |     size_t zret;  | 
581  |  |     int ret;  | 
582  |  |     ZSTD_outBuffer outBuf;  | 
583  |  |     BIO *next = BIO_next(b);  | 
584  |  |  | 
585  |  |     if (out == NULL || outl <= 0)  | 
586  |  |         return 0;  | 
587  |  |  | 
588  |  |     ctx = BIO_get_data(b);  | 
589  |  |     BIO_clear_retry_flags(b);  | 
590  |  |     if (ctx->decompress.buffer == NULL) { | 
591  |  |         ctx->decompress.buffer = OPENSSL_malloc(ctx->decompress.bufsize);  | 
592  |  |         if (ctx->decompress.buffer == NULL) { | 
593  |  |             ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);  | 
594  |  |             return 0;  | 
595  |  |         }  | 
596  |  |         ctx->decompress.inbuf.src = ctx->decompress.buffer;  | 
597  |  |         ctx->decompress.inbuf.size = 0;  | 
598  |  |         ctx->decompress.inbuf.pos = 0;  | 
599  |  |     }  | 
600  |  |  | 
601  |  |     /* Copy output data directly to supplied buffer */  | 
602  |  |     outBuf.dst = out;  | 
603  |  |     outBuf.size = (size_t)outl;  | 
604  |  |     outBuf.pos = 0;  | 
605  |  |     for (;;) { | 
606  |  |         /* Decompress while data available */  | 
607  |  |         do { | 
608  |  |             zret = ZSTD_decompressStream(ctx->decompress.state, &outBuf, &ctx->decompress.inbuf);  | 
609  |  |             if (ZSTD_isError(zret)) { | 
610  |  |                 ERR_raise(ERR_LIB_COMP, COMP_R_ZSTD_DECOMPRESS_ERROR);  | 
611  |  |                 ERR_add_error_data(1, ZSTD_getErrorName(zret));  | 
612  |  |                 return -1;  | 
613  |  |             }  | 
614  |  |             /* No more output space */  | 
615  |  |             if (outBuf.pos == outBuf.size)  | 
616  |  |                 return outBuf.pos;  | 
617  |  |         } while (ctx->decompress.inbuf.pos < ctx->decompress.inbuf.size);  | 
618  |  |  | 
619  |  |         /*  | 
620  |  |          * No data in input buffer try to read some in, if an error then  | 
621  |  |          * return the total data read.  | 
622  |  |          */  | 
623  |  |         ret = BIO_read(next, ctx->decompress.buffer, ctx->decompress.bufsize);  | 
624  |  |         if (ret <= 0) { | 
625  |  |             BIO_copy_next_retry(b);  | 
626  |  |             if (ret < 0 && outBuf.pos == 0)  | 
627  |  |                 return ret;  | 
628  |  |             return outBuf.pos;  | 
629  |  |         }  | 
630  |  |         ctx->decompress.inbuf.size = ret;  | 
631  |  |         ctx->decompress.inbuf.pos = 0;  | 
632  |  |     }  | 
633  |  | }  | 
634  |  |  | 
635  |  | static int bio_zstd_write(BIO *b, const char *in, int inl)  | 
636  |  | { | 
637  |  |     BIO_ZSTD_CTX *ctx;  | 
638  |  |     size_t zret;  | 
639  |  |     ZSTD_inBuffer inBuf;  | 
640  |  |     int ret;  | 
641  |  |     int done = 0;  | 
642  |  |     BIO *next = BIO_next(b);  | 
643  |  |  | 
644  |  |     if (in == NULL || inl <= 0)  | 
645  |  |         return 0;  | 
646  |  |  | 
647  |  |     ctx = BIO_get_data(b);  | 
648  |  |  | 
649  |  |     BIO_clear_retry_flags(b);  | 
650  |  |     if (ctx->compress.outbuf.dst == NULL) { | 
651  |  |         ctx->compress.outbuf.dst = OPENSSL_malloc(ctx->compress.bufsize);  | 
652  |  |         if (ctx->compress.outbuf.dst == NULL) { | 
653  |  |             ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);  | 
654  |  |             return 0;  | 
655  |  |         }  | 
656  |  |         ctx->compress.outbuf.size = ctx->compress.bufsize;  | 
657  |  |         ctx->compress.outbuf.pos = 0;  | 
658  |  |         ctx->compress.write_pos = 0;  | 
659  |  |     }  | 
660  |  |     /* Obtain input data directly from supplied buffer */  | 
661  |  |     inBuf.src = in;  | 
662  |  |     inBuf.size = inl;  | 
663  |  |     inBuf.pos = 0;  | 
664  |  |     for (;;) { | 
665  |  |         /* If data in output buffer write it first */  | 
666  |  |         while (ctx->compress.write_pos < ctx->compress.outbuf.pos) { | 
667  |  |             ret = BIO_write(next, (unsigned char*)ctx->compress.outbuf.dst + ctx->compress.write_pos,  | 
668  |  |                             ctx->compress.outbuf.pos - ctx->compress.write_pos);  | 
669  |  |             if (ret <= 0) { | 
670  |  |                 BIO_copy_next_retry(b);  | 
671  |  |                 if (ret < 0 && inBuf.pos == 0)  | 
672  |  |                     return ret;  | 
673  |  |                 return inBuf.pos;  | 
674  |  |             }  | 
675  |  |             ctx->compress.write_pos += ret;  | 
676  |  |         }  | 
677  |  |  | 
678  |  |         /* Have we consumed all supplied data? */  | 
679  |  |         if (done)  | 
680  |  |             return inBuf.pos;  | 
681  |  |  | 
682  |  |         /* Reset buffer */  | 
683  |  |         ctx->compress.outbuf.pos = 0;  | 
684  |  |         ctx->compress.outbuf.size = ctx->compress.bufsize;  | 
685  |  |         ctx->compress.write_pos = 0;  | 
686  |  |         /* Compress some more */  | 
687  |  |         zret = ZSTD_compressStream2(ctx->compress.state, &ctx->compress.outbuf, &inBuf, ZSTD_e_end);  | 
688  |  |         if (ZSTD_isError(zret)) { | 
689  |  |             ERR_raise(ERR_LIB_COMP, COMP_R_ZSTD_COMPRESS_ERROR);  | 
690  |  |             ERR_add_error_data(1, ZSTD_getErrorName(zret));  | 
691  |  |             return 0;  | 
692  |  |         } else if (zret == 0) { | 
693  |  |             done = 1;  | 
694  |  |         }  | 
695  |  |     }  | 
696  |  | }  | 
697  |  |  | 
698  |  | static int bio_zstd_flush(BIO *b)  | 
699  |  | { | 
700  |  |     BIO_ZSTD_CTX *ctx;  | 
701  |  |     size_t zret;  | 
702  |  |     int ret;  | 
703  |  |     BIO *next = BIO_next(b);  | 
704  |  |  | 
705  |  |     ctx = BIO_get_data(b);  | 
706  |  |  | 
707  |  |     /* If no data written or already flush show success */  | 
708  |  |     if (ctx->compress.outbuf.dst == NULL)  | 
709  |  |         return 1;  | 
710  |  |  | 
711  |  |     BIO_clear_retry_flags(b);  | 
712  |  |     /* No more input data */  | 
713  |  |     ctx->compress.outbuf.pos = 0;  | 
714  |  |     ctx->compress.outbuf.size = ctx->compress.bufsize;  | 
715  |  |     ctx->compress.write_pos = 0;  | 
716  |  |     for (;;) { | 
717  |  |         /* If data in output buffer write it first */  | 
718  |  |         while (ctx->compress.write_pos < ctx->compress.outbuf.pos) { | 
719  |  |             ret = BIO_write(next, (unsigned char*)ctx->compress.outbuf.dst + ctx->compress.write_pos,  | 
720  |  |                             ctx->compress.outbuf.pos - ctx->compress.write_pos);  | 
721  |  |             if (ret <= 0) { | 
722  |  |                 BIO_copy_next_retry(b);  | 
723  |  |                 return ret;  | 
724  |  |             }  | 
725  |  |             ctx->compress.write_pos += ret;  | 
726  |  |         }  | 
727  |  |  | 
728  |  |         /* Reset buffer */  | 
729  |  |         ctx->compress.outbuf.pos = 0;  | 
730  |  |         ctx->compress.outbuf.size = ctx->compress.bufsize;  | 
731  |  |         ctx->compress.write_pos = 0;  | 
732  |  |         /* Compress some more */  | 
733  |  |         zret = ZSTD_flushStream(ctx->compress.state, &ctx->compress.outbuf);  | 
734  |  |         if (ZSTD_isError(zret)) { | 
735  |  |             ERR_raise(ERR_LIB_COMP, COMP_R_ZSTD_DECODE_ERROR);  | 
736  |  |             ERR_add_error_data(1, ZSTD_getErrorName(zret));  | 
737  |  |             return 0;  | 
738  |  |         }  | 
739  |  |         if (zret == 0)  | 
740  |  |             return 1;  | 
741  |  |     }  | 
742  |  | }  | 
743  |  |  | 
744  |  | static long bio_zstd_ctrl(BIO *b, int cmd, long num, void *ptr)  | 
745  |  | { | 
746  |  |     BIO_ZSTD_CTX *ctx;  | 
747  |  |     int ret = 0, *ip;  | 
748  |  |     size_t ibs, obs;  | 
749  |  |     unsigned char *tmp;  | 
750  |  |     BIO *next = BIO_next(b);  | 
751  |  |  | 
752  |  |     if (next == NULL)  | 
753  |  |         return 0;  | 
754  |  |     ctx = BIO_get_data(b);  | 
755  |  |     switch (cmd) { | 
756  |  |  | 
757  |  |     case BIO_CTRL_RESET:  | 
758  |  |         ctx->compress.write_pos = 0;  | 
759  |  |         ctx->compress.bufsize = 0;  | 
760  |  |         ret = 1;  | 
761  |  |         break;  | 
762  |  |  | 
763  |  |     case BIO_CTRL_FLUSH:  | 
764  |  |         ret = bio_zstd_flush(b);  | 
765  |  |         if (ret > 0) { | 
766  |  |             ret = BIO_flush(next);  | 
767  |  |             BIO_copy_next_retry(b);  | 
768  |  |         }  | 
769  |  |         break;  | 
770  |  |  | 
771  |  |     case BIO_C_SET_BUFF_SIZE:  | 
772  |  |         ibs = ctx->decompress.bufsize;  | 
773  |  |         obs = ctx->compress.bufsize;  | 
774  |  |         if (ptr != NULL) { | 
775  |  |             ip = ptr;  | 
776  |  |             if (*ip == 0)  | 
777  |  |                 ibs = (size_t)num;  | 
778  |  |             else  | 
779  |  |                 obs = (size_t)num;  | 
780  |  |         } else { | 
781  |  |             obs = ibs = (size_t)num;  | 
782  |  |         }  | 
783  |  |  | 
784  |  |         if (ibs > 0 && ibs != ctx->decompress.bufsize) { | 
785  |  |             if (ctx->decompress.buffer != NULL) { | 
786  |  |                 tmp = OPENSSL_realloc(ctx->decompress.buffer, ibs);  | 
787  |  |                 if (tmp == NULL)  | 
788  |  |                     return 0;  | 
789  |  |                 if (ctx->decompress.inbuf.src == ctx->decompress.buffer)  | 
790  |  |                     ctx->decompress.inbuf.src = tmp;  | 
791  |  |                 ctx->decompress.buffer = tmp;  | 
792  |  |             }  | 
793  |  |             ctx->decompress.bufsize = ibs;  | 
794  |  |         }  | 
795  |  |  | 
796  |  |         if (obs > 0 && obs != ctx->compress.bufsize) { | 
797  |  |             if (ctx->compress.outbuf.dst != NULL) { | 
798  |  |                 tmp = OPENSSL_realloc(ctx->compress.outbuf.dst, obs);  | 
799  |  |                 if (tmp == NULL)  | 
800  |  |                     return 0;  | 
801  |  |                 ctx->compress.outbuf.dst = tmp;  | 
802  |  |             }  | 
803  |  |             ctx->compress.bufsize = obs;  | 
804  |  |         }  | 
805  |  |         ret = 1;  | 
806  |  |         break;  | 
807  |  |  | 
808  |  |     case BIO_C_DO_STATE_MACHINE:  | 
809  |  |         BIO_clear_retry_flags(b);  | 
810  |  |         ret = BIO_ctrl(next, cmd, num, ptr);  | 
811  |  |         BIO_copy_next_retry(b);  | 
812  |  |         break;  | 
813  |  |  | 
814  |  |    case BIO_CTRL_WPENDING:  | 
815  |  |         if (ctx->compress.outbuf.pos < ctx->compress.outbuf.size)  | 
816  |  |             ret = 1;  | 
817  |  |         else  | 
818  |  |             ret = BIO_ctrl(next, cmd, num, ptr);  | 
819  |  |         break;  | 
820  |  |  | 
821  |  |     case BIO_CTRL_PENDING:  | 
822  |  |         if (ctx->decompress.inbuf.pos < ctx->decompress.inbuf.size)  | 
823  |  |             ret = 1;  | 
824  |  |         else  | 
825  |  |             ret = BIO_ctrl(next, cmd, num, ptr);  | 
826  |  |         break;  | 
827  |  |  | 
828  |  |     default:  | 
829  |  |         ret = BIO_ctrl(next, cmd, num, ptr);  | 
830  |  |         break;  | 
831  |  |  | 
832  |  |     }  | 
833  |  |  | 
834  |  |     return ret;  | 
835  |  | }  | 
836  |  |  | 
837  |  | static long bio_zstd_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)  | 
838  |  | { | 
839  |  |     BIO *next = BIO_next(b);  | 
840  |  |     if (next == NULL)  | 
841  |  |         return 0;  | 
842  |  |     return BIO_callback_ctrl(next, cmd, fp);  | 
843  |  | }  | 
844  |  |  | 
845  |  | #endif  |