mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-10 01:40:17 +01:00
506 lines
13 KiB
C
506 lines
13 KiB
C
|
/* ***** BEGIN LICENSE BLOCK *****
|
||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||
|
*
|
||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||
|
* the License. You may obtain a copy of the License at
|
||
|
* http://www.mozilla.org/MPL/
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
|
* for the specific language governing rights and limitations under the
|
||
|
* License.
|
||
|
*
|
||
|
* The Original Code is the Netscape security libraries.
|
||
|
*
|
||
|
* The Initial Developer of the Original Code is
|
||
|
* Netscape Communications Corporation.
|
||
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
||
|
* the Initial Developer. All Rights Reserved.
|
||
|
*
|
||
|
* Contributor(s):
|
||
|
*
|
||
|
* Alternatively, the contents of this file may be used under the terms of
|
||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||
|
* of those above. If you wish to allow use of your version of this file only
|
||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||
|
* use your version of this file under the terms of the MPL, indicate your
|
||
|
* decision by deleting the provisions above and replace them with the notice
|
||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||
|
* the provisions above, a recipient may use your version of this file under
|
||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||
|
*
|
||
|
* ***** END LICENSE BLOCK ***** */
|
||
|
|
||
|
#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, optional, 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;
|
||
|
optional = (encode_kind & DER_OPTIONAL) ? 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(PRArenaPool *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;
|
||
|
}
|