derdec.c (5408B)
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 = (int)(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 }