mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-14 03:30:17 +01:00
44b7f056d9
bug1001332, 56b691c003ad, bug1086145, bug1054069, bug1155922, bug991783, bug1125025, bug1162521, bug1162644, bug1132941, bug1164364, bug1166205, bug1166163, bug1166515, bug1138554, bug1167046, bug1167043, bug1169451, bug1172128, bug1170322, bug102794, bug1128184, bug557830, bug1174648, bug1180244, bug1177784, bug1173413, bug1169174, bug1084669, bug951455, bug1183395, bug1177430, bug1183827, bug1160139, bug1154106, bug1142209, bug1185033, bug1193467, bug1182667(with sha512 changes backed out, which breaks VC6 compilation), bug1158489, bug337796
473 lines
11 KiB
C
473 lines
11 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "secder.h"
|
|
#include "secerr.h"
|
|
|
|
#if 0
|
|
/*
|
|
* Generic templates for individual/simple items.
|
|
*/
|
|
|
|
DERTemplate SECAnyTemplate[] = {
|
|
{ DER_ANY,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECBitStringTemplate[] = {
|
|
{ DER_BIT_STRING,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECBooleanTemplate[] = {
|
|
{ DER_BOOLEAN,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECIA5StringTemplate[] = {
|
|
{ DER_IA5_STRING,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECIntegerTemplate[] = {
|
|
{ DER_INTEGER,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECNullTemplate[] = {
|
|
{ DER_NULL,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECObjectIDTemplate[] = {
|
|
{ DER_OBJECT_ID,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECOctetStringTemplate[] = {
|
|
{ DER_OCTET_STRING,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECPrintableStringTemplate[] = {
|
|
{ DER_PRINTABLE_STRING,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECT61StringTemplate[] = {
|
|
{ DER_T61_STRING,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
DERTemplate SECUTCTimeTemplate[] = {
|
|
{ DER_UTC_TIME,
|
|
0, NULL, sizeof(SECItem) }
|
|
};
|
|
|
|
#endif
|
|
|
|
static int
|
|
header_length(DERTemplate *dtemplate, PRUint32 contents_len)
|
|
{
|
|
PRUint32 len;
|
|
unsigned long encode_kind, under_kind;
|
|
PRBool explicit, optional, universal;
|
|
|
|
encode_kind = dtemplate->kind;
|
|
|
|
explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
|
|
optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
|
|
universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
PORT_Assert (!(explicit && universal)); /* bad templates */
|
|
|
|
if (encode_kind & DER_POINTER) {
|
|
if (dtemplate->sub != NULL) {
|
|
under_kind = dtemplate->sub->kind;
|
|
if (universal) {
|
|
encode_kind = under_kind;
|
|
}
|
|
} else if (universal) {
|
|
under_kind = encode_kind & ~DER_POINTER;
|
|
} else {
|
|
under_kind = dtemplate->arg;
|
|
}
|
|
} else if (encode_kind & DER_INLINE) {
|
|
PORT_Assert (dtemplate->sub != NULL);
|
|
under_kind = dtemplate->sub->kind;
|
|
if (universal) {
|
|
encode_kind = under_kind;
|
|
}
|
|
} else if (universal) {
|
|
under_kind = encode_kind;
|
|
} else {
|
|
under_kind = dtemplate->arg;
|
|
}
|
|
|
|
/* This is only used in decoding; it plays no part in encoding. */
|
|
if (under_kind & DER_DERPTR)
|
|
return 0;
|
|
|
|
/* No header at all for an "empty" optional. */
|
|
if ((contents_len == 0) && optional)
|
|
return 0;
|
|
|
|
/* And no header for a full DER_ANY. */
|
|
if (encode_kind & DER_ANY)
|
|
return 0;
|
|
|
|
/*
|
|
* The common case: one octet for identifier and as many octets
|
|
* as necessary to hold the content length.
|
|
*/
|
|
len = 1 + DER_LengthLength(contents_len);
|
|
|
|
/* Account for the explicit wrapper, if necessary. */
|
|
if (explicit) {
|
|
#if 0 /*
|
|
* Well, I was trying to do something useful, but these
|
|
* assertions are too restrictive on valid templates.
|
|
* I wanted to make sure that the top-level "kind" of
|
|
* a template does not also specify DER_EXPLICIT, which
|
|
* should only modify a component field. Maybe later
|
|
* I can figure out a better way to detect such a problem,
|
|
* but for now I must remove these checks altogether.
|
|
*/
|
|
/*
|
|
* This modifier applies only to components of a set or sequence;
|
|
* it should never be used on a set/sequence itself -- confirm.
|
|
*/
|
|
PORT_Assert (under_kind != DER_SEQUENCE);
|
|
PORT_Assert (under_kind != DER_SET);
|
|
#endif
|
|
|
|
len += 1 + DER_LengthLength(len + contents_len);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
static PRUint32
|
|
contents_length(DERTemplate *dtemplate, void *src)
|
|
{
|
|
PRUint32 len;
|
|
unsigned long encode_kind, under_kind;
|
|
PRBool universal;
|
|
|
|
|
|
PORT_Assert (src != NULL);
|
|
|
|
encode_kind = dtemplate->kind;
|
|
|
|
universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
|
|
? PR_TRUE : PR_FALSE;
|
|
encode_kind &= ~DER_OPTIONAL;
|
|
|
|
if (encode_kind & DER_POINTER) {
|
|
src = *(void **)src;
|
|
if (src == NULL) {
|
|
return 0;
|
|
}
|
|
if (dtemplate->sub != NULL) {
|
|
dtemplate = dtemplate->sub;
|
|
under_kind = dtemplate->kind;
|
|
src = (void *)((char *)src + dtemplate->offset);
|
|
} else if (universal) {
|
|
under_kind = encode_kind & ~DER_POINTER;
|
|
} else {
|
|
under_kind = dtemplate->arg;
|
|
}
|
|
} else if (encode_kind & DER_INLINE) {
|
|
PORT_Assert (dtemplate->sub != NULL);
|
|
dtemplate = dtemplate->sub;
|
|
under_kind = dtemplate->kind;
|
|
src = (void *)((char *)src + dtemplate->offset);
|
|
} else if (universal) {
|
|
under_kind = encode_kind;
|
|
} else {
|
|
under_kind = dtemplate->arg;
|
|
}
|
|
|
|
/* Having any of these bits is not expected here... */
|
|
PORT_Assert ((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL
|
|
| DER_POINTER | DER_SKIP)) == 0);
|
|
|
|
/* This is only used in decoding; it plays no part in encoding. */
|
|
if (under_kind & DER_DERPTR)
|
|
return 0;
|
|
|
|
if (under_kind & DER_INDEFINITE) {
|
|
PRUint32 sub_len;
|
|
void **indp = *(void ***)src;
|
|
|
|
if (indp == NULL)
|
|
return 0;
|
|
|
|
len = 0;
|
|
under_kind &= ~DER_INDEFINITE;
|
|
|
|
if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
|
|
DERTemplate *tmpt = dtemplate->sub;
|
|
PORT_Assert (tmpt != NULL);
|
|
|
|
for (; *indp != NULL; indp++) {
|
|
void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
|
|
sub_len = contents_length (tmpt, sub_src);
|
|
len += sub_len + header_length (tmpt, sub_len);
|
|
}
|
|
} else {
|
|
/*
|
|
* XXX Lisa is not sure this code (for handling, for example,
|
|
* DER_INDEFINITE | DER_OCTET_STRING) is right.
|
|
*/
|
|
for (; *indp != NULL; indp++) {
|
|
SECItem *item = (SECItem *)(*indp);
|
|
sub_len = item->len;
|
|
if (under_kind == DER_BIT_STRING) {
|
|
sub_len = (sub_len + 7) >> 3;
|
|
/* bit string contents involve an extra octet */
|
|
if (sub_len)
|
|
sub_len++;
|
|
}
|
|
if (under_kind != DER_ANY)
|
|
len += 1 + DER_LengthLength (sub_len);
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
switch (under_kind) {
|
|
case DER_SEQUENCE:
|
|
case DER_SET:
|
|
{
|
|
DERTemplate *tmpt;
|
|
void *sub_src;
|
|
PRUint32 sub_len;
|
|
|
|
len = 0;
|
|
for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
|
|
sub_src = (void *)((char *)src + tmpt->offset);
|
|
sub_len = contents_length (tmpt, sub_src);
|
|
len += sub_len + header_length (tmpt, sub_len);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DER_BIT_STRING:
|
|
len = (((SECItem *)src)->len + 7) >> 3;
|
|
/* bit string contents involve an extra octet */
|
|
if (len)
|
|
len++;
|
|
break;
|
|
|
|
default:
|
|
len = ((SECItem *)src)->len;
|
|
break;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
static unsigned char *
|
|
der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src)
|
|
{
|
|
int header_len;
|
|
PRUint32 contents_len;
|
|
unsigned long encode_kind, under_kind;
|
|
PRBool explicit, universal;
|
|
|
|
|
|
/*
|
|
* First figure out how long the encoding will be. Do this by
|
|
* traversing the template from top to bottom and accumulating
|
|
* the length of each leaf item.
|
|
*/
|
|
contents_len = contents_length (dtemplate, src);
|
|
header_len = header_length (dtemplate, contents_len);
|
|
|
|
/*
|
|
* Enough smarts was involved already, so that if both the
|
|
* header and the contents have a length of zero, then we
|
|
* are not doing any encoding for this element.
|
|
*/
|
|
if (header_len == 0 && contents_len == 0)
|
|
return buf;
|
|
|
|
encode_kind = dtemplate->kind;
|
|
|
|
explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
|
|
encode_kind &= ~DER_OPTIONAL;
|
|
universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
|
|
? PR_TRUE : PR_FALSE;
|
|
|
|
if (encode_kind & DER_POINTER) {
|
|
if (contents_len) {
|
|
src = *(void **)src;
|
|
PORT_Assert (src != NULL);
|
|
}
|
|
if (dtemplate->sub != NULL) {
|
|
dtemplate = dtemplate->sub;
|
|
under_kind = dtemplate->kind;
|
|
if (universal) {
|
|
encode_kind = under_kind;
|
|
}
|
|
src = (void *)((char *)src + dtemplate->offset);
|
|
} else if (universal) {
|
|
under_kind = encode_kind & ~DER_POINTER;
|
|
} else {
|
|
under_kind = dtemplate->arg;
|
|
}
|
|
} else if (encode_kind & DER_INLINE) {
|
|
dtemplate = dtemplate->sub;
|
|
under_kind = dtemplate->kind;
|
|
if (universal) {
|
|
encode_kind = under_kind;
|
|
}
|
|
src = (void *)((char *)src + dtemplate->offset);
|
|
} else if (universal) {
|
|
under_kind = encode_kind;
|
|
} else {
|
|
under_kind = dtemplate->arg;
|
|
}
|
|
|
|
if (explicit) {
|
|
buf = DER_StoreHeader (buf, encode_kind,
|
|
(1 + DER_LengthLength(contents_len)
|
|
+ contents_len));
|
|
encode_kind = under_kind;
|
|
}
|
|
|
|
if ((encode_kind & DER_ANY) == 0) { /* DER_ANY already contains header */
|
|
buf = DER_StoreHeader (buf, encode_kind, contents_len);
|
|
}
|
|
|
|
/* If no real contents to encode, then we are done. */
|
|
if (contents_len == 0)
|
|
return buf;
|
|
|
|
if (under_kind & DER_INDEFINITE) {
|
|
void **indp;
|
|
|
|
indp = *(void ***)src;
|
|
PORT_Assert (indp != NULL);
|
|
|
|
under_kind &= ~DER_INDEFINITE;
|
|
if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
|
|
DERTemplate *tmpt = dtemplate->sub;
|
|
PORT_Assert (tmpt != NULL);
|
|
for (; *indp != NULL; indp++) {
|
|
void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
|
|
buf = der_encode (buf, tmpt, sub_src);
|
|
}
|
|
} else {
|
|
for (; *indp != NULL; indp++) {
|
|
SECItem *item;
|
|
int sub_len;
|
|
|
|
item = (SECItem *)(*indp);
|
|
sub_len = item->len;
|
|
if (under_kind == DER_BIT_STRING) {
|
|
if (sub_len) {
|
|
int rem;
|
|
|
|
sub_len = (sub_len + 7) >> 3;
|
|
buf = DER_StoreHeader (buf, under_kind, sub_len + 1);
|
|
rem = (sub_len << 3) - item->len;
|
|
*buf++ = rem; /* remaining bits */
|
|
} else {
|
|
buf = DER_StoreHeader (buf, under_kind, 0);
|
|
}
|
|
} else if (under_kind != DER_ANY) {
|
|
buf = DER_StoreHeader (buf, under_kind, sub_len);
|
|
}
|
|
PORT_Memcpy (buf, item->data, sub_len);
|
|
buf += sub_len;
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
switch (under_kind) {
|
|
case DER_SEQUENCE:
|
|
case DER_SET:
|
|
{
|
|
DERTemplate *tmpt;
|
|
void *sub_src;
|
|
|
|
for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
|
|
sub_src = (void *)((char *)src + tmpt->offset);
|
|
buf = der_encode (buf, tmpt, sub_src);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DER_BIT_STRING:
|
|
{
|
|
SECItem *item;
|
|
int rem;
|
|
|
|
/*
|
|
* The contents length includes our extra octet; subtract
|
|
* it off so we just have the real string length there.
|
|
*/
|
|
contents_len--;
|
|
item = (SECItem *)src;
|
|
PORT_Assert (contents_len == ((item->len + 7) >> 3));
|
|
rem = (contents_len << 3) - item->len;
|
|
*buf++ = rem; /* remaining bits */
|
|
PORT_Memcpy (buf, item->data, contents_len);
|
|
buf += contents_len;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
SECItem *item;
|
|
|
|
item = (SECItem *)src;
|
|
PORT_Assert (contents_len == item->len);
|
|
PORT_Memcpy (buf, item->data, contents_len);
|
|
buf += contents_len;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
|
|
SECStatus
|
|
DER_Encode(PLArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src)
|
|
{
|
|
unsigned int contents_len, header_len;
|
|
|
|
src = (void **)((char *)src + dtemplate->offset);
|
|
|
|
/*
|
|
* First figure out how long the encoding will be. Do this by
|
|
* traversing the template from top to bottom and accumulating
|
|
* the length of each leaf item.
|
|
*/
|
|
contents_len = contents_length (dtemplate, src);
|
|
header_len = header_length (dtemplate, contents_len);
|
|
|
|
dest->len = contents_len + header_len;
|
|
|
|
/* Allocate storage to hold the encoding */
|
|
dest->data = (unsigned char*) PORT_ArenaAlloc(arena, dest->len);
|
|
if (dest->data == NULL) {
|
|
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
|
return SECFailure;
|
|
}
|
|
|
|
/* Now encode into the buffer */
|
|
(void) der_encode (dest->data, dtemplate, src);
|
|
|
|
return SECSuccess;
|
|
}
|