derenc.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 505 行

C
505
字号
/* * 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 Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "secder.h"#include "secerr.h"/* * 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) }};static intheader_length(DERTemplate *dtemplate, uint32 contents_len){    uint32 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) {	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 uint32contents_length(DERTemplate *dtemplate, void *src){    uint32 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) {	uint32 sub_len;	void **indp;	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;	    void *sub_src;	    tmpt = dtemplate->sub;	    for (; *indp != NULL; indp++) {		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;		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;	    uint32 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;    uint32 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;	    void *sub_src;	    tmpt = dtemplate->sub;	    for (; *indp != NULL; indp++) {		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;}SECStatusDER_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;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?