security/nss/lib/util/derdec.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial