]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/asn1/bio_asn1.c
Create BIO_read_ex() which handles size_t arguments
[thirdparty/openssl.git] / crypto / asn1 / bio_asn1.c
CommitLineData
0f113f3e 1/*
b1322259 2 * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
11d8cdc6 3 *
b1322259
RS
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
11d8cdc6
DSH
8 */
9
0f113f3e
MC
10/*
11 * Experimental ASN1 BIO. When written through the data is converted to an
12 * ASN1 string type: default is OCTET STRING. Additional functions can be
13 * provided to add prefix and suffix data.
11d8cdc6
DSH
14 */
15
16#include <string.h>
a146ae55 17#include <internal/bio.h>
11d8cdc6
DSH
18#include <openssl/asn1.h>
19
20/* Must be large enough for biggest tag+length */
21#define DEFAULT_ASN1_BUF_SIZE 20
22
0f113f3e
MC
23typedef enum {
24 ASN1_STATE_START,
25 ASN1_STATE_PRE_COPY,
26 ASN1_STATE_HEADER,
27 ASN1_STATE_HEADER_COPY,
28 ASN1_STATE_DATA_COPY,
29 ASN1_STATE_POST_COPY,
30 ASN1_STATE_DONE
31} asn1_bio_state_t;
32
33typedef struct BIO_ASN1_EX_FUNCS_st {
34 asn1_ps_func *ex_func;
35 asn1_ps_func *ex_free_func;
36} BIO_ASN1_EX_FUNCS;
37
38typedef struct BIO_ASN1_BUF_CTX_t {
39 /* Internal state */
40 asn1_bio_state_t state;
41 /* Internal buffer */
42 unsigned char *buf;
43 /* Size of buffer */
44 int bufsize;
45 /* Current position in buffer */
46 int bufpos;
47 /* Current buffer length */
48 int buflen;
49 /* Amount of data to copy */
50 int copylen;
51 /* Class and tag to use */
52 int asn1_class, asn1_tag;
53 asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
54 /* Extra buffer for prefix and suffix data */
55 unsigned char *ex_buf;
56 int ex_len;
57 int ex_pos;
58 void *ex_arg;
59} BIO_ASN1_BUF_CTX;
60
61static int asn1_bio_write(BIO *h, const char *buf, int num);
11d8cdc6
DSH
62static int asn1_bio_read(BIO *h, char *buf, int size);
63static int asn1_bio_puts(BIO *h, const char *str);
64static int asn1_bio_gets(BIO *h, char *str, int size);
65static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
66static int asn1_bio_new(BIO *h);
67static int asn1_bio_free(BIO *data);
68static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
69
70static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
71static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
0f113f3e 72 asn1_ps_func *cleanup, asn1_bio_state_t next);
11d8cdc6 73static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
0f113f3e
MC
74 asn1_ps_func *setup,
75 asn1_bio_state_t ex_state,
76 asn1_bio_state_t other_state);
77
04f6b0fd 78static const BIO_METHOD methods_asn1 = {
0f113f3e
MC
79 BIO_TYPE_ASN1,
80 "asn1",
81 asn1_bio_write,
d07aee2c
MC
82 /* TODO: Convert to new style read function */
83 bread_conv,
0f113f3e
MC
84 asn1_bio_read,
85 asn1_bio_puts,
86 asn1_bio_gets,
87 asn1_bio_ctrl,
88 asn1_bio_new,
89 asn1_bio_free,
90 asn1_bio_callback_ctrl,
91};
11d8cdc6 92
04f6b0fd 93const BIO_METHOD *BIO_f_asn1(void)
0f113f3e
MC
94{
95 return (&methods_asn1);
96}
11d8cdc6
DSH
97
98static int asn1_bio_new(BIO *b)
0f113f3e 99{
f59f23c3 100 BIO_ASN1_BUF_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
8e89e85f 101
90945fa3 102 if (ctx == NULL)
0f113f3e
MC
103 return 0;
104 if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) {
105 OPENSSL_free(ctx);
106 return 0;
107 }
a146ae55
MC
108 BIO_set_data(b, ctx);
109 BIO_set_init(b, 1);
110
0f113f3e
MC
111 return 1;
112}
11d8cdc6
DSH
113
114static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
0f113f3e
MC
115{
116 ctx->buf = OPENSSL_malloc(size);
90945fa3 117 if (ctx->buf == NULL)
0f113f3e
MC
118 return 0;
119 ctx->bufsize = size;
0f113f3e
MC
120 ctx->asn1_class = V_ASN1_UNIVERSAL;
121 ctx->asn1_tag = V_ASN1_OCTET_STRING;
0f113f3e
MC
122 ctx->state = ASN1_STATE_START;
123 return 1;
124}
11d8cdc6
DSH
125
126static int asn1_bio_free(BIO *b)
0f113f3e 127{
a146ae55
MC
128 BIO_ASN1_BUF_CTX *ctx;
129
130 if (b == NULL)
131 return 0;
ca3a82c3 132
a146ae55 133 ctx = BIO_get_data(b);
0f113f3e
MC
134 if (ctx == NULL)
135 return 0;
a146ae55 136
b548a1f1 137 OPENSSL_free(ctx->buf);
0f113f3e 138 OPENSSL_free(ctx);
a146ae55
MC
139 BIO_set_data(b, NULL);
140 BIO_set_init(b, 0);
141
0f113f3e
MC
142 return 1;
143}
144
145static int asn1_bio_write(BIO *b, const char *in, int inl)
146{
147 BIO_ASN1_BUF_CTX *ctx;
148 int wrmax, wrlen, ret;
149 unsigned char *p;
a146ae55
MC
150 BIO *next;
151
152 ctx = BIO_get_data(b);
153 next = BIO_next(b);
154 if (in == NULL || inl < 0 || ctx == NULL || next == NULL)
0f113f3e
MC
155 return 0;
156
157 wrlen = 0;
158 ret = -1;
159
160 for (;;) {
161 switch (ctx->state) {
0f113f3e
MC
162 /* Setup prefix data, call it */
163 case ASN1_STATE_START:
164 if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
165 ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
166 return 0;
167 break;
168
169 /* Copy any pre data first */
170 case ASN1_STATE_PRE_COPY:
171
172 ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
173 ASN1_STATE_HEADER);
174
175 if (ret <= 0)
176 goto done;
177
178 break;
179
180 case ASN1_STATE_HEADER:
181 ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
182 OPENSSL_assert(ctx->buflen <= ctx->bufsize);
183 p = ctx->buf;
184 ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class);
185 ctx->copylen = inl;
186 ctx->state = ASN1_STATE_HEADER_COPY;
187
188 break;
189
190 case ASN1_STATE_HEADER_COPY:
a146ae55 191 ret = BIO_write(next, ctx->buf + ctx->bufpos, ctx->buflen);
0f113f3e
MC
192 if (ret <= 0)
193 goto done;
194
195 ctx->buflen -= ret;
196 if (ctx->buflen)
197 ctx->bufpos += ret;
198 else {
199 ctx->bufpos = 0;
200 ctx->state = ASN1_STATE_DATA_COPY;
201 }
202
203 break;
204
205 case ASN1_STATE_DATA_COPY:
206
207 if (inl > ctx->copylen)
208 wrmax = ctx->copylen;
209 else
210 wrmax = inl;
a146ae55 211 ret = BIO_write(next, in, wrmax);
0f113f3e
MC
212 if (ret <= 0)
213 break;
214 wrlen += ret;
215 ctx->copylen -= ret;
216 in += ret;
217 inl -= ret;
218
219 if (ctx->copylen == 0)
220 ctx->state = ASN1_STATE_HEADER;
221
222 if (inl == 0)
223 goto done;
224
225 break;
226
f3b3d7f0
RS
227 case ASN1_STATE_POST_COPY:
228 case ASN1_STATE_DONE:
0f113f3e
MC
229 BIO_clear_retry_flags(b);
230 return 0;
231
232 }
233
234 }
235
236 done:
237 BIO_clear_retry_flags(b);
238 BIO_copy_next_retry(b);
239
240 return (wrlen > 0) ? wrlen : ret;
241
242}
11d8cdc6
DSH
243
244static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
0f113f3e
MC
245 asn1_ps_func *cleanup, asn1_bio_state_t next)
246{
247 int ret;
a146ae55 248
0f113f3e
MC
249 if (ctx->ex_len <= 0)
250 return 1;
251 for (;;) {
a146ae55 252 ret = BIO_write(BIO_next(b), ctx->ex_buf + ctx->ex_pos, ctx->ex_len);
0f113f3e
MC
253 if (ret <= 0)
254 break;
255 ctx->ex_len -= ret;
256 if (ctx->ex_len > 0)
257 ctx->ex_pos += ret;
258 else {
259 if (cleanup)
260 cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
261 ctx->state = next;
262 ctx->ex_pos = 0;
263 break;
264 }
265 }
266 return ret;
267}
11d8cdc6
DSH
268
269static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
0f113f3e
MC
270 asn1_ps_func *setup,
271 asn1_bio_state_t ex_state,
272 asn1_bio_state_t other_state)
273{
274 if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) {
275 BIO_clear_retry_flags(b);
276 return 0;
277 }
278 if (ctx->ex_len > 0)
279 ctx->state = ex_state;
280 else
281 ctx->state = other_state;
282 return 1;
283}
284
285static int asn1_bio_read(BIO *b, char *in, int inl)
286{
a146ae55
MC
287 BIO *next = BIO_next(b);
288 if (next == NULL)
0f113f3e 289 return 0;
a146ae55 290 return BIO_read(next, in, inl);
0f113f3e 291}
11d8cdc6
DSH
292
293static int asn1_bio_puts(BIO *b, const char *str)
0f113f3e
MC
294{
295 return asn1_bio_write(b, str, strlen(str));
296}
11d8cdc6
DSH
297
298static int asn1_bio_gets(BIO *b, char *str, int size)
0f113f3e 299{
a146ae55
MC
300 BIO *next = BIO_next(b);
301 if (next == NULL)
0f113f3e 302 return 0;
a146ae55 303 return BIO_gets(next, str, size);
0f113f3e 304}
11d8cdc6
DSH
305
306static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
0f113f3e 307{
a146ae55
MC
308 BIO *next = BIO_next(b);
309 if (next == NULL)
310 return 0;
311 return BIO_callback_ctrl(next, cmd, fp);
0f113f3e 312}
11d8cdc6
DSH
313
314static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
0f113f3e
MC
315{
316 BIO_ASN1_BUF_CTX *ctx;
317 BIO_ASN1_EX_FUNCS *ex_func;
318 long ret = 1;
a146ae55
MC
319 BIO *next;
320
321 ctx = BIO_get_data(b);
0f113f3e
MC
322 if (ctx == NULL)
323 return 0;
a146ae55 324 next = BIO_next(b);
0f113f3e
MC
325 switch (cmd) {
326
327 case BIO_C_SET_PREFIX:
328 ex_func = arg2;
329 ctx->prefix = ex_func->ex_func;
330 ctx->prefix_free = ex_func->ex_free_func;
331 break;
332
333 case BIO_C_GET_PREFIX:
334 ex_func = arg2;
335 ex_func->ex_func = ctx->prefix;
336 ex_func->ex_free_func = ctx->prefix_free;
337 break;
338
339 case BIO_C_SET_SUFFIX:
340 ex_func = arg2;
341 ctx->suffix = ex_func->ex_func;
342 ctx->suffix_free = ex_func->ex_free_func;
343 break;
344
345 case BIO_C_GET_SUFFIX:
346 ex_func = arg2;
347 ex_func->ex_func = ctx->suffix;
348 ex_func->ex_free_func = ctx->suffix_free;
349 break;
350
351 case BIO_C_SET_EX_ARG:
352 ctx->ex_arg = arg2;
353 break;
354
355 case BIO_C_GET_EX_ARG:
356 *(void **)arg2 = ctx->ex_arg;
357 break;
358
359 case BIO_CTRL_FLUSH:
a146ae55 360 if (next == NULL)
0f113f3e
MC
361 return 0;
362
363 /* Call post function if possible */
364 if (ctx->state == ASN1_STATE_HEADER) {
365 if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
366 ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
367 return 0;
368 }
369
370 if (ctx->state == ASN1_STATE_POST_COPY) {
371 ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
372 ASN1_STATE_DONE);
373 if (ret <= 0)
374 return ret;
375 }
376
377 if (ctx->state == ASN1_STATE_DONE)
a146ae55 378 return BIO_ctrl(next, cmd, arg1, arg2);
0f113f3e
MC
379 else {
380 BIO_clear_retry_flags(b);
381 return 0;
382 }
0f113f3e
MC
383
384 default:
a146ae55 385 if (next == NULL)
0f113f3e 386 return 0;
a146ae55 387 return BIO_ctrl(next, cmd, arg1, arg2);
0f113f3e
MC
388
389 }
390
391 return ret;
392}
11d8cdc6
DSH
393
394static int asn1_bio_set_ex(BIO *b, int cmd,
0f113f3e
MC
395 asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
396{
397 BIO_ASN1_EX_FUNCS extmp;
398 extmp.ex_func = ex_func;
399 extmp.ex_free_func = ex_free_func;
400 return BIO_ctrl(b, cmd, 0, &extmp);
401}
11d8cdc6
DSH
402
403static int asn1_bio_get_ex(BIO *b, int cmd,
0f113f3e
MC
404 asn1_ps_func **ex_func,
405 asn1_ps_func **ex_free_func)
406{
407 BIO_ASN1_EX_FUNCS extmp;
408 int ret;
409 ret = BIO_ctrl(b, cmd, 0, &extmp);
410 if (ret > 0) {
411 *ex_func = extmp.ex_func;
412 *ex_free_func = extmp.ex_free_func;
413 }
414 return ret;
415}
416
417int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
418 asn1_ps_func *prefix_free)
419{
420 return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
421}
422
423int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
424 asn1_ps_func **pprefix_free)
425{
426 return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
427}
428
429int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
430 asn1_ps_func *suffix_free)
431{
432 return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
433}
434
435int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
436 asn1_ps_func **psuffix_free)
437{
438 return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
439}