/ libder / derr.c
derr.c
  1  #include <string.h>
  2  #include "derr.h"
  3  #include "der-private.h"
  4  
  5  int derr_peek(unsigned int *der_class, _Bool *constructed,
  6                unsigned int *der_tag, size_t *der_len,
  7                derr_byte **pp, size_t *runlen)
  8  {
  9    unsigned int cls, tag;
 10    _Bool constr;
 11    size_t l;
 12    derr_byte *p = *pp;
 13    size_t rl = *runlen;
 14  
 15    cls = *p & 0xC0;
 16    constr = !!(*p &0x20);
 17    tag = *p & 0x1F;
 18  
 19    if (tag == 31) {
 20      tag = 0;
 21      do {
 22        p++;
 23        rl--;
 24        tag <<= 7;
 25        tag += *p & 0x7F;
 26      } while (*p & 0x80);
 27    }
 28  
 29    l = *++p;
 30    rl--;
 31    if (l & 0x80) {
 32      size_t n = l & 0x7F;
 33  
 34      for (l = 0; n-- > 0;) {
 35        l <<= 8;
 36        l += *++p;
 37        rl--;
 38      }
 39    }
 40    p++;
 41    rl--;
 42  
 43    *der_class = cls;
 44    *constructed = constr;
 45    *der_tag = tag;
 46    if (der_len != NULL)
 47      *der_len = l;
 48    *pp = p;
 49    *runlen = rl;
 50    return 1;
 51  }
 52  
 53  int derr_header(unsigned int der_class, _Bool constructed, unsigned int der_tag,
 54                  size_t *contents_length, derr_byte **pp, size_t *runlen)
 55  {
 56    unsigned int cls, tag;
 57    _Bool constr;
 58    size_t l;
 59    derr_byte *p = *pp;
 60    size_t rl = *runlen;
 61  
 62    if (!derr_peek(&cls, &constr, &tag,
 63                   contents_length, &p, &rl))
 64      return 0;
 65    if (cls != der_class || constr != constructed || tag != der_tag)
 66      return 0;
 67  
 68    *pp = p;
 69    *runlen = rl;
 70    return 1;
 71  }
 72  
 73  int derr_contents(void *contents, size_t contents_size,
 74                    derr_byte **pp, size_t *runlen)
 75  {
 76    if (contents_size > *runlen)
 77      return 0;
 78    if (contents != NULL)
 79      memcpy(contents, *pp, contents_size);
 80    *pp += contents_size;
 81    *runlen -= contents_size;
 82    return 1;
 83  }
 84  
 85  int derr(unsigned int der_class, _Bool constructed, unsigned int der_tag,
 86           void *contents, size_t contents_size, size_t *contents_length,
 87           derr_byte **pp, size_t *runlen)
 88  {
 89    if (!derr_header(der_class, constructed, der_tag,
 90                     contents_length, pp, runlen))
 91      return 0;
 92    if (*contents_length > contents_size)
 93      return 0;
 94    if (!derr_contents(contents, *contents_length, pp, runlen))
 95      return 0;
 96    return 1;
 97  }
 98  
 99  /*
100   * DERR_BEGIN1() and DERR_END1() are for functions that use derr_peek(),
101   * i.e. only advance past the tag and length.
102   */
103  #define DERR_BEGIN1(d_context, d_tag, d_runlen, d_pp, d_my_l, d_my_p)   \
104    int derr_context = d_context;                                         \
105    unsigned int derr_class = ((derr_context < 0)                         \
106                               ? DERC_UNIVERSAL                           \
107                               : DERC_CONTEXT);                           \
108    unsigned int derr_tag = ((derr_context < 0)                           \
109                             ? DERP_##d_tag                               \
110                             : (unsigned int)derr_context);               \
111    _Bool derr_constructed = IS_##d_tag##_CONSTRUCTED;                    \
112    derr_byte *derr_pp = *d_pp;                                           \
113    size_t derr_rl = *d_runlen;                                           \
114    size_t derr_l = 0;                                                    \
115                                                                          \
116    size_t d_my_l = 0;                                                    \
117    derr_byte *d_my_p = NULL;                                             \
118    if (!derr_header(derr_class, derr_constructed, derr_tag,              \
119                     &derr_l, &derr_pp, &derr_rl))                        \
120      return 0;                                                           \
121    d_my_p = derr_pp;                                                     \
122    d_my_l = derr_l
123  
124  #define DERR_END1(d_pp, d_runlen)                                       \
125    *d_pp = derr_pp + derr_l;                                             \
126    *d_runlen = derr_rl - derr_l
127  
128  int derr_boolean(_Bool *boolean, int context, derr_byte **pp, size_t *runlen)
129  {
130    DERR_BEGIN1(context, BOOLEAN, runlen, pp, l, p);
131  
132    switch (*p) {
133    case 0x00:
134    case 0xFF:
135      *boolean = !!(*p);
136      break;
137    default:
138      return 0;
139    }
140  
141    DERR_END1(pp, runlen);
142    return 1;
143  }
144  
145  int derr_unsigned_integer(uintmax_t *i, int context,
146                            derr_byte **pp, size_t *runlen)
147  {
148    size_t pi = 0;
149    DERR_BEGIN1(context, INTEGER, runlen, pp, l, p);
150  
151    /* An unsigned integer cannot start with a high bit set */
152    if ((p[0] & 0x80) != 0)
153      return 0;
154    /* Skip past a leading zero if followed by a byte with the high bit set */
155    if (p[0] == 0 && (1 < l || (p[1] & 0x80) == 0))
156      pi++;
157    /* If the first byte at this point is zero, this isn't DER */
158    if (l - pi > 1 && p[pi] == 0)
159      return 0;
160  
161    /* Size check */
162    if (l - pi > sizeof(*i))
163      return 0;
164  
165    for(*i = 0; pi < l; pi++)
166      *i = (*i << 8) | p[pi];
167  
168    DERR_END1(pp, runlen);
169    return 1;
170  }
171  
172  int derr_integer(intmax_t *i, int context, derr_byte **pp, size_t *runlen)
173  {
174    size_t pi = 0;
175    DERR_BEGIN1(context, INTEGER, runlen, pp, l, p);
176  
177    /* If the first byte at this point is zero */
178    if (l - pi > 1 && p[pi] == 0)
179      return 0;
180  
181    /* Size check */
182    if (l - pi > sizeof(*i))
183      return 0;
184  
185    for(*i = 0; pi < l; pi++)
186      *i = (*i << 8) | p[pi];
187  
188    DERR_END1(pp, runlen);
189    return 1;
190  }