| OLD | NEW |
| (Empty) |
| 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 | |
| 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 | |
| 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 = bp - buf; | |
| 179 *contents_len_p = contents_len; | |
| 180 | |
| 181 return SECSuccess; | |
| 182 } | |
| 183 | |
| 184 SECStatus | |
| 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 } | |
| OLD | NEW |