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 }