Coverage Report

Created: 2022-08-24 06:30

/src/libressl/crypto/asn1/bio_asn1.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD: bio_asn1.c,v 1.17 2022/01/14 08:40:57 tb Exp $ */
2
/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3
 * project.
4
 */
5
/* ====================================================================
6
 * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 *
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 *
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in
17
 *    the documentation and/or other materials provided with the
18
 *    distribution.
19
 *
20
 * 3. All advertising materials mentioning features or use of this
21
 *    software must display the following acknowledgment:
22
 *    "This product includes software developed by the OpenSSL Project
23
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24
 *
25
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26
 *    endorse or promote products derived from this software without
27
 *    prior written permission. For written permission, please contact
28
 *    licensing@OpenSSL.org.
29
 *
30
 * 5. Products derived from this software may not be called "OpenSSL"
31
 *    nor may "OpenSSL" appear in their names without prior written
32
 *    permission of the OpenSSL Project.
33
 *
34
 * 6. Redistributions of any form whatsoever must retain the following
35
 *    acknowledgment:
36
 *    "This product includes software developed by the OpenSSL Project
37
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38
 *
39
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50
 * OF THE POSSIBILITY OF SUCH DAMAGE.
51
 * ====================================================================
52
 *
53
 * This product includes cryptographic software written by Eric Young
54
 * (eay@cryptsoft.com).  This product includes software written by Tim
55
 * Hudson (tjh@cryptsoft.com).
56
 *
57
 */
58
59
/* Experimental ASN1 BIO. When written through the data is converted
60
 * to an ASN1 string type: default is OCTET STRING. Additional functions
61
 * can be provided to add prefix and suffix data.
62
 */
63
64
#include <stdlib.h>
65
#include <string.h>
66
67
#include <openssl/bio.h>
68
#include <openssl/asn1.h>
69
70
#include "bio_local.h"
71
72
/* Must be large enough for biggest tag+length */
73
0
#define DEFAULT_ASN1_BUF_SIZE 20
74
75
typedef enum {
76
  ASN1_STATE_START,
77
  ASN1_STATE_PRE_COPY,
78
  ASN1_STATE_HEADER,
79
  ASN1_STATE_HEADER_COPY,
80
  ASN1_STATE_DATA_COPY,
81
  ASN1_STATE_POST_COPY,
82
  ASN1_STATE_DONE
83
} asn1_bio_state_t;
84
85
typedef struct BIO_ASN1_EX_FUNCS_st {
86
  asn1_ps_func  *ex_func;
87
  asn1_ps_func  *ex_free_func;
88
} BIO_ASN1_EX_FUNCS;
89
90
typedef struct BIO_ASN1_BUF_CTX_t {
91
  /* Internal state */
92
  asn1_bio_state_t state;
93
  /* Internal buffer */
94
  unsigned char *buf;
95
  /* Size of buffer */
96
  int bufsize;
97
  /* Current position in buffer */
98
  int bufpos;
99
  /* Current buffer length */
100
  int buflen;
101
  /* Amount of data to copy */
102
  int copylen;
103
  /* Class and tag to use */
104
  int asn1_class, asn1_tag;
105
  asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
106
  /* Extra buffer for prefix and suffix data */
107
  unsigned char *ex_buf;
108
  int ex_len;
109
  int ex_pos;
110
  void *ex_arg;
111
} BIO_ASN1_BUF_CTX;
112
113
114
static int asn1_bio_write(BIO *h, const char *buf, int num);
115
static int asn1_bio_read(BIO *h, char *buf, int size);
116
static int asn1_bio_puts(BIO *h, const char *str);
117
static int asn1_bio_gets(BIO *h, char *str, int size);
118
static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
119
static int asn1_bio_new(BIO *h);
120
static int asn1_bio_free(BIO *data);
121
static long asn1_bio_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
122
123
static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
124
    asn1_ps_func *cleanup, asn1_bio_state_t next);
125
static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
126
    asn1_ps_func *setup, asn1_bio_state_t ex_state,
127
    asn1_bio_state_t other_state);
128
129
static const BIO_METHOD methods_asn1 = {
130
  .type = BIO_TYPE_ASN1,
131
  .name = "asn1",
132
  .bwrite = asn1_bio_write,
133
  .bread = asn1_bio_read,
134
  .bputs = asn1_bio_puts,
135
  .bgets = asn1_bio_gets,
136
  .ctrl = asn1_bio_ctrl,
137
  .create = asn1_bio_new,
138
  .destroy = asn1_bio_free,
139
  .callback_ctrl = asn1_bio_callback_ctrl
140
};
141
142
const BIO_METHOD *
143
BIO_f_asn1(void)
144
0
{
145
0
  return (&methods_asn1);
146
0
}
147
148
static int
149
asn1_bio_new(BIO *b)
150
0
{
151
0
  BIO_ASN1_BUF_CTX *ctx;
152
153
0
  if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
154
0
    return 0;
155
156
0
  if ((ctx->buf = malloc(DEFAULT_ASN1_BUF_SIZE)) == NULL) {
157
0
    free(ctx);
158
0
    return 0;
159
0
  }
160
0
  ctx->bufsize = DEFAULT_ASN1_BUF_SIZE;
161
0
  ctx->asn1_class = V_ASN1_UNIVERSAL;
162
0
  ctx->asn1_tag = V_ASN1_OCTET_STRING;
163
0
  ctx->state = ASN1_STATE_START;
164
165
0
  b->init = 1;
166
0
  b->ptr = (char *)ctx;
167
0
  b->flags = 0;
168
169
0
  return 1;
170
0
}
171
172
static int
173
asn1_bio_free(BIO *b)
174
0
{
175
0
  BIO_ASN1_BUF_CTX *ctx;
176
177
0
  ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
178
0
  if (ctx == NULL)
179
0
    return 0;
180
0
  free(ctx->buf);
181
0
  free(ctx);
182
0
  b->init = 0;
183
0
  b->ptr = NULL;
184
0
  b->flags = 0;
185
0
  return 1;
186
0
}
187
188
static int
189
asn1_bio_write(BIO *b, const char *in , int inl)
190
0
{
191
0
  BIO_ASN1_BUF_CTX *ctx;
192
0
  int wrmax, wrlen, ret, buflen;
193
0
  unsigned char *p;
194
195
0
  if (!in || (inl < 0) || (b->next_bio == NULL))
196
0
    return 0;
197
0
  ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
198
0
  if (ctx == NULL)
199
0
    return 0;
200
201
0
  wrlen = 0;
202
0
  ret = -1;
203
204
0
  for (;;) {
205
0
    switch (ctx->state) {
206
207
      /* Setup prefix data, call it */
208
0
    case ASN1_STATE_START:
209
0
      if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
210
0
            ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
211
0
        return 0;
212
0
      break;
213
214
      /* Copy any pre data first */
215
0
    case ASN1_STATE_PRE_COPY:
216
0
      ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
217
0
          ASN1_STATE_HEADER);
218
0
      if (ret <= 0)
219
0
        goto done;
220
0
      break;
221
222
0
    case ASN1_STATE_HEADER:
223
0
      buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
224
0
      if (buflen <= 0 || buflen > ctx->bufsize)
225
0
        return -1;
226
0
      ctx->buflen = buflen;
227
0
      p = ctx->buf;
228
0
      ASN1_put_object(&p, 0, inl,
229
0
          ctx->asn1_tag, ctx->asn1_class);
230
0
      ctx->copylen = inl;
231
0
      ctx->state = ASN1_STATE_HEADER_COPY;
232
0
      break;
233
234
0
    case ASN1_STATE_HEADER_COPY:
235
0
      ret = BIO_write(b->next_bio,
236
0
          ctx->buf + ctx->bufpos, ctx->buflen);
237
0
      if (ret <= 0)
238
0
        goto done;
239
240
0
      ctx->buflen -= ret;
241
0
      if (ctx->buflen)
242
0
        ctx->bufpos += ret;
243
0
      else {
244
0
        ctx->bufpos = 0;
245
0
        ctx->state = ASN1_STATE_DATA_COPY;
246
0
      }
247
0
      break;
248
249
0
    case ASN1_STATE_DATA_COPY:
250
251
0
      if (inl > ctx->copylen)
252
0
        wrmax = ctx->copylen;
253
0
      else
254
0
        wrmax = inl;
255
0
      ret = BIO_write(b->next_bio, in, wrmax);
256
0
      if (ret <= 0)
257
0
        break;
258
0
      wrlen += ret;
259
0
      ctx->copylen -= ret;
260
0
      in += ret;
261
0
      inl -= ret;
262
263
0
      if (ctx->copylen == 0)
264
0
        ctx->state = ASN1_STATE_HEADER;
265
0
      if (inl == 0)
266
0
        goto done;
267
0
      break;
268
269
0
    default:
270
0
      BIO_clear_retry_flags(b);
271
0
      return 0;
272
0
    }
273
274
0
  }
275
276
0
 done:
277
0
  BIO_clear_retry_flags(b);
278
0
  BIO_copy_next_retry(b);
279
280
0
  return (wrlen > 0) ? wrlen : ret;
281
0
}
282
283
static int
284
asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, asn1_ps_func *cleanup,
285
    asn1_bio_state_t next)
286
0
{
287
0
  int ret;
288
289
0
  if (ctx->ex_len <= 0)
290
0
    return 1;
291
0
  for (;;) {
292
0
    ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos,
293
0
        ctx->ex_len);
294
0
    if (ret <= 0)
295
0
      break;
296
0
    ctx->ex_len -= ret;
297
0
    if (ctx->ex_len > 0)
298
0
      ctx->ex_pos += ret;
299
0
    else {
300
0
      if (cleanup)
301
0
        cleanup(b, &ctx->ex_buf, &ctx->ex_len,
302
0
            &ctx->ex_arg);
303
0
      ctx->state = next;
304
0
      ctx->ex_pos = 0;
305
0
      break;
306
0
    }
307
0
  }
308
0
  return ret;
309
0
}
310
311
static int
312
asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, asn1_ps_func *setup,
313
    asn1_bio_state_t ex_state, asn1_bio_state_t other_state)
314
0
{
315
0
  if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) {
316
0
    BIO_clear_retry_flags(b);
317
0
    return 0;
318
0
  }
319
0
  if (ctx->ex_len > 0)
320
0
    ctx->state = ex_state;
321
0
  else
322
0
    ctx->state = other_state;
323
0
  return 1;
324
0
}
325
326
static int
327
asn1_bio_read(BIO *b, char *in , int inl)
328
0
{
329
0
  if (!b->next_bio)
330
0
    return 0;
331
0
  return BIO_read(b->next_bio, in , inl);
332
0
}
333
334
static int
335
asn1_bio_puts(BIO *b, const char *str)
336
0
{
337
0
  return asn1_bio_write(b, str, strlen(str));
338
0
}
339
340
static int
341
asn1_bio_gets(BIO *b, char *str, int size)
342
0
{
343
0
  if (!b->next_bio)
344
0
    return 0;
345
0
  return BIO_gets(b->next_bio, str , size);
346
0
}
347
348
static long
349
asn1_bio_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
350
0
{
351
0
  if (b->next_bio == NULL)
352
0
    return (0);
353
0
  return BIO_callback_ctrl(b->next_bio, cmd, fp);
354
0
}
355
356
static long
357
asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
358
0
{
359
0
  BIO_ASN1_BUF_CTX *ctx;
360
0
  BIO_ASN1_EX_FUNCS *ex_func;
361
0
  long ret = 1;
362
363
0
  ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
364
0
  if (ctx == NULL)
365
0
    return 0;
366
0
  switch (cmd) {
367
368
0
  case BIO_C_SET_PREFIX:
369
0
    ex_func = arg2;
370
0
    ctx->prefix = ex_func->ex_func;
371
0
    ctx->prefix_free = ex_func->ex_free_func;
372
0
    break;
373
374
0
  case BIO_C_GET_PREFIX:
375
0
    ex_func = arg2;
376
0
    ex_func->ex_func = ctx->prefix;
377
0
    ex_func->ex_free_func = ctx->prefix_free;
378
0
    break;
379
380
0
  case BIO_C_SET_SUFFIX:
381
0
    ex_func = arg2;
382
0
    ctx->suffix = ex_func->ex_func;
383
0
    ctx->suffix_free = ex_func->ex_free_func;
384
0
    break;
385
386
0
  case BIO_C_GET_SUFFIX:
387
0
    ex_func = arg2;
388
0
    ex_func->ex_func = ctx->suffix;
389
0
    ex_func->ex_free_func = ctx->suffix_free;
390
0
    break;
391
392
0
  case BIO_C_SET_EX_ARG:
393
0
    ctx->ex_arg = arg2;
394
0
    break;
395
396
0
  case BIO_C_GET_EX_ARG:
397
0
    *(void **)arg2 = ctx->ex_arg;
398
0
    break;
399
400
0
  case BIO_CTRL_FLUSH:
401
0
    if (!b->next_bio)
402
0
      return 0;
403
404
    /* Call post function if possible */
405
0
    if (ctx->state == ASN1_STATE_HEADER) {
406
0
      if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
407
0
          ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
408
0
        return 0;
409
0
    }
410
411
0
    if (ctx->state == ASN1_STATE_POST_COPY) {
412
0
      ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
413
0
          ASN1_STATE_DONE);
414
0
      if (ret <= 0)
415
0
        return ret;
416
0
    }
417
418
0
    if (ctx->state == ASN1_STATE_DONE)
419
0
      return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
420
0
    else {
421
0
      BIO_clear_retry_flags(b);
422
0
      return 0;
423
0
    }
424
0
    break;
425
426
427
0
  default:
428
0
    if (!b->next_bio)
429
0
      return 0;
430
0
    return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
431
432
0
  }
433
434
0
  return ret;
435
0
}
436
437
static int
438
asn1_bio_set_ex(BIO *b, int cmd, asn1_ps_func *ex_func, asn1_ps_func
439
    *ex_free_func)
440
0
{
441
0
  BIO_ASN1_EX_FUNCS extmp;
442
443
0
  extmp.ex_func = ex_func;
444
0
  extmp.ex_free_func = ex_free_func;
445
0
  return BIO_ctrl(b, cmd, 0, &extmp);
446
0
}
447
448
static int
449
asn1_bio_get_ex(BIO *b, int cmd, asn1_ps_func **ex_func,
450
    asn1_ps_func **ex_free_func)
451
0
{
452
0
  BIO_ASN1_EX_FUNCS extmp;
453
0
  int ret;
454
455
0
  ret = BIO_ctrl(b, cmd, 0, &extmp);
456
0
  if (ret > 0) {
457
0
    *ex_func = extmp.ex_func;
458
0
    *ex_free_func = extmp.ex_free_func;
459
0
  }
460
0
  return ret;
461
0
}
462
463
int
464
BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free)
465
0
{
466
0
  return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
467
0
}
468
469
int
470
BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free)
471
0
{
472
0
  return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
473
0
}
474
475
int
476
BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free)
477
0
{
478
0
  return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
479
0
}
480
481
int
482
BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free)
483
0
{
484
0
  return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
485
0
}