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