michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "secder.h" michael@0: #include michael@0: #include "secerr.h" michael@0: michael@0: int michael@0: DER_LengthLength(PRUint32 len) michael@0: { michael@0: if (len > 127) { michael@0: if (len > 255) { michael@0: if (len > 65535L) { michael@0: if (len > 16777215L) { michael@0: return 5; michael@0: } else { michael@0: return 4; michael@0: } michael@0: } else { michael@0: return 3; michael@0: } michael@0: } else { michael@0: return 2; michael@0: } michael@0: } else { michael@0: return 1; michael@0: } michael@0: } michael@0: michael@0: unsigned char * michael@0: DER_StoreHeader(unsigned char *buf, unsigned int code, PRUint32 len) michael@0: { michael@0: unsigned char b[4]; michael@0: michael@0: b[0] = (unsigned char)(len >> 24); michael@0: b[1] = (unsigned char)(len >> 16); michael@0: b[2] = (unsigned char)(len >> 8); michael@0: b[3] = (unsigned char)len; michael@0: if ((code & DER_TAGNUM_MASK) == DER_SET michael@0: || (code & DER_TAGNUM_MASK) == DER_SEQUENCE) michael@0: code |= DER_CONSTRUCTED; michael@0: *buf++ = code; michael@0: if (len > 127) { michael@0: if (len > 255) { michael@0: if (len > 65535) { michael@0: if (len > 16777215) { michael@0: *buf++ = 0x84; michael@0: *buf++ = b[0]; michael@0: *buf++ = b[1]; michael@0: *buf++ = b[2]; michael@0: *buf++ = b[3]; michael@0: } else { michael@0: *buf++ = 0x83; michael@0: *buf++ = b[1]; michael@0: *buf++ = b[2]; michael@0: *buf++ = b[3]; michael@0: } michael@0: } else { michael@0: *buf++ = 0x82; michael@0: *buf++ = b[2]; michael@0: *buf++ = b[3]; michael@0: } michael@0: } else { michael@0: *buf++ = 0x81; michael@0: *buf++ = b[3]; michael@0: } michael@0: } else { michael@0: *buf++ = b[3]; michael@0: } michael@0: return buf; michael@0: } michael@0: michael@0: /* michael@0: * XXX This should be rewritten, generalized, to take a long instead michael@0: * of a PRInt32. michael@0: */ michael@0: SECStatus michael@0: DER_SetInteger(PLArenaPool *arena, SECItem *it, PRInt32 i) michael@0: { michael@0: unsigned char bb[4]; michael@0: unsigned len; michael@0: michael@0: bb[0] = (unsigned char) (i >> 24); michael@0: bb[1] = (unsigned char) (i >> 16); michael@0: bb[2] = (unsigned char) (i >> 8); michael@0: bb[3] = (unsigned char) (i); michael@0: michael@0: /* michael@0: ** Small integers are encoded in a single byte. Larger integers michael@0: ** require progressively more space. michael@0: */ michael@0: if (i < -128) { michael@0: if (i < -32768L) { michael@0: if (i < -8388608L) { michael@0: len = 4; michael@0: } else { michael@0: len = 3; michael@0: } michael@0: } else { michael@0: len = 2; michael@0: } michael@0: } else if (i > 127) { michael@0: if (i > 32767L) { michael@0: if (i > 8388607L) { michael@0: len = 4; michael@0: } else { michael@0: len = 3; michael@0: } michael@0: } else { michael@0: len = 2; michael@0: } michael@0: } else { michael@0: len = 1; michael@0: } michael@0: it->data = (unsigned char*) PORT_ArenaAlloc(arena, len); michael@0: if (!it->data) { michael@0: return SECFailure; michael@0: } michael@0: it->len = len; michael@0: PORT_Memcpy(it->data, bb + (4 - len), len); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: /* michael@0: * XXX This should be rewritten, generalized, to take an unsigned long instead michael@0: * of a PRUint32. michael@0: */ michael@0: SECStatus michael@0: DER_SetUInteger(PLArenaPool *arena, SECItem *it, PRUint32 ui) michael@0: { michael@0: unsigned char bb[5]; michael@0: int len; michael@0: michael@0: bb[0] = 0; michael@0: bb[1] = (unsigned char) (ui >> 24); michael@0: bb[2] = (unsigned char) (ui >> 16); michael@0: bb[3] = (unsigned char) (ui >> 8); michael@0: bb[4] = (unsigned char) (ui); michael@0: michael@0: /* michael@0: ** Small integers are encoded in a single byte. Larger integers michael@0: ** require progressively more space. michael@0: */ michael@0: if (ui > 0x7f) { michael@0: if (ui > 0x7fff) { michael@0: if (ui > 0x7fffffL) { michael@0: if (ui >= 0x80000000L) { michael@0: len = 5; michael@0: } else { michael@0: len = 4; michael@0: } michael@0: } else { michael@0: len = 3; michael@0: } michael@0: } else { michael@0: len = 2; michael@0: } michael@0: } else { michael@0: len = 1; michael@0: } michael@0: michael@0: it->data = (unsigned char *)PORT_ArenaAlloc(arena, len); michael@0: if (it->data == NULL) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: it->len = len; michael@0: PORT_Memcpy(it->data, bb + (sizeof(bb) - len), len); michael@0: michael@0: return SECSuccess; michael@0: } michael@0: michael@0: /* michael@0: ** Convert a der encoded *signed* integer into a machine integral value. michael@0: ** If an underflow/overflow occurs, sets error code and returns min/max. michael@0: */ michael@0: long michael@0: DER_GetInteger(const SECItem *it) michael@0: { michael@0: long ival = 0; michael@0: unsigned len = it->len; michael@0: unsigned char *cp = it->data; michael@0: unsigned long overflow = 0x1ffUL << (((sizeof(ival) - 1) * 8) - 1); michael@0: unsigned long ofloinit; michael@0: michael@0: PORT_Assert(len); michael@0: if (!len) { michael@0: PORT_SetError(SEC_ERROR_INPUT_LEN); michael@0: return 0; michael@0: } michael@0: michael@0: if (*cp & 0x80) michael@0: ival = -1L; michael@0: ofloinit = ival & overflow; michael@0: michael@0: while (len) { michael@0: if ((ival & overflow) != ofloinit) { michael@0: PORT_SetError(SEC_ERROR_BAD_DER); michael@0: if (ival < 0) { michael@0: return LONG_MIN; michael@0: } michael@0: return LONG_MAX; michael@0: } michael@0: ival = ival << 8; michael@0: ival |= *cp++; michael@0: --len; michael@0: } michael@0: return ival; michael@0: } michael@0: michael@0: /* michael@0: ** Convert a der encoded *unsigned* integer into a machine integral value. michael@0: ** If an overflow occurs, sets error code and returns max. michael@0: */ michael@0: unsigned long michael@0: DER_GetUInteger(SECItem *it) michael@0: { michael@0: unsigned long ival = 0; michael@0: unsigned len = it->len; michael@0: unsigned char *cp = it->data; michael@0: unsigned long overflow = 0xffUL << ((sizeof(ival) - 1) * 8); michael@0: michael@0: PORT_Assert(len); michael@0: if (!len) { michael@0: PORT_SetError(SEC_ERROR_INPUT_LEN); michael@0: return 0; michael@0: } michael@0: michael@0: /* Cannot put a negative value into an unsigned container. */ michael@0: if (*cp & 0x80) { michael@0: PORT_SetError(SEC_ERROR_BAD_DER); michael@0: return 0; michael@0: } michael@0: michael@0: while (len) { michael@0: if (ival & overflow) { michael@0: PORT_SetError(SEC_ERROR_BAD_DER); michael@0: return ULONG_MAX; michael@0: } michael@0: ival = ival << 8; michael@0: ival |= *cp++; michael@0: --len; michael@0: } michael@0: return ival; michael@0: }