1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "secder.h"
6 #include "secerr.h"
7
8 static PRUint32
der_indefinite_length(unsigned char * buf,unsigned char * end)9 der_indefinite_length(unsigned char *buf, unsigned char *end)
10 {
11 PRUint32 len, ret, dataLen;
12 unsigned char tag, lenCode;
13 int dataLenLen;
14
15 len = 0;
16 while (1) {
17 if ((buf + 2) > end) {
18 return (0);
19 }
20
21 tag = *buf++;
22 lenCode = *buf++;
23 len += 2;
24
25 if ((tag == 0) && (lenCode == 0)) {
26 return (len);
27 }
28
29 if (lenCode == 0x80) { /* indefinite length */
30 ret = der_indefinite_length(buf, end); /* recurse to find length */
31 if (ret == 0)
32 return 0;
33 len += ret;
34 buf += ret;
35 } else { /* definite length */
36 if (lenCode & 0x80) {
37 /* Length of data is in multibyte format */
38 dataLenLen = lenCode & 0x7f;
39 switch (dataLenLen) {
40 case 1:
41 dataLen = buf[0];
42 break;
43 case 2:
44 dataLen = (buf[0] << 8) | buf[1];
45 break;
46 case 3:
47 dataLen = ((unsigned long)buf[0] << 16) | (buf[1] << 8) | buf[2];
48 break;
49 case 4:
50 dataLen = ((unsigned long)buf[0] << 24) |
51 ((unsigned long)buf[1] << 16) | (buf[2] << 8) | buf[3];
52 break;
53 default:
54 PORT_SetError(SEC_ERROR_BAD_DER);
55 return SECFailure;
56 }
57 } else {
58 /* Length of data is in single byte */
59 dataLen = lenCode;
60 dataLenLen = 0;
61 }
62
63 /* skip this item */
64 buf = buf + dataLenLen + dataLen;
65 len = len + dataLenLen + dataLen;
66 }
67 }
68 }
69
70 /*
71 ** Capture the next thing in the buffer.
72 ** Returns the length of the header and the length of the contents.
73 */
74 static SECStatus
der_capture(unsigned char * buf,unsigned char * end,int * header_len_p,PRUint32 * contents_len_p)75 der_capture(unsigned char *buf, unsigned char *end,
76 int *header_len_p, PRUint32 *contents_len_p)
77 {
78 unsigned char *bp;
79 unsigned char whole_tag;
80 PRUint32 contents_len;
81 int tag_number;
82
83 if ((buf + 2) > end) {
84 *header_len_p = 0;
85 *contents_len_p = 0;
86 if (buf == end)
87 return SECSuccess;
88 return SECFailure;
89 }
90
91 bp = buf;
92
93 /* Get tag and verify that it is ok. */
94 whole_tag = *bp++;
95 tag_number = whole_tag & DER_TAGNUM_MASK;
96
97 /*
98 * XXX This code does not (yet) handle the high-tag-number form!
99 */
100 if (tag_number == DER_HIGH_TAG_NUMBER) {
101 PORT_SetError(SEC_ERROR_BAD_DER);
102 return SECFailure;
103 }
104
105 if ((whole_tag & DER_CLASS_MASK) == DER_UNIVERSAL) {
106 /* Check that the universal tag number is one we implement. */
107 switch (tag_number) {
108 case DER_BOOLEAN:
109 case DER_INTEGER:
110 case DER_BIT_STRING:
111 case DER_OCTET_STRING:
112 case DER_NULL:
113 case DER_OBJECT_ID:
114 case DER_SEQUENCE:
115 case DER_SET:
116 case DER_PRINTABLE_STRING:
117 case DER_T61_STRING:
118 case DER_IA5_STRING:
119 case DER_VISIBLE_STRING:
120 case DER_UTC_TIME:
121 case 0: /* end-of-contents tag */
122 break;
123 default:
124 PORT_SetError(SEC_ERROR_BAD_DER);
125 return SECFailure;
126 }
127 }
128
129 /*
130 * Get first byte of length code (might contain entire length, might not).
131 */
132 contents_len = *bp++;
133
134 /*
135 * If the high bit is set, then the length is in multibyte format,
136 * or the thing has an indefinite-length.
137 */
138 if (contents_len & 0x80) {
139 int bytes_of_encoded_len;
140
141 bytes_of_encoded_len = contents_len & 0x7f;
142 contents_len = 0;
143
144 switch (bytes_of_encoded_len) {
145 case 4:
146 contents_len |= *bp++;
147 contents_len <<= 8;
148 /* fallthru */
149 case 3:
150 contents_len |= *bp++;
151 contents_len <<= 8;
152 /* fallthru */
153 case 2:
154 contents_len |= *bp++;
155 contents_len <<= 8;
156 /* fallthru */
157 case 1:
158 contents_len |= *bp++;
159 break;
160
161 case 0:
162 contents_len = der_indefinite_length(bp, end);
163 if (contents_len)
164 break;
165 /* fallthru */
166 default:
167 PORT_SetError(SEC_ERROR_BAD_DER);
168 return SECFailure;
169 }
170 }
171
172 if ((bp + contents_len) > end) {
173 /* Ran past end of buffer */
174 PORT_SetError(SEC_ERROR_BAD_DER);
175 return SECFailure;
176 }
177
178 *header_len_p = (int)(bp - buf);
179 *contents_len_p = contents_len;
180
181 return SECSuccess;
182 }
183
184 SECStatus
DER_Lengths(SECItem * item,int * header_len_p,PRUint32 * contents_len_p)185 DER_Lengths(SECItem *item, int *header_len_p, PRUint32 *contents_len_p)
186 {
187 return (der_capture(item->data, &item->data[item->len], header_len_p,
188 contents_len_p));
189 }
190