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