Mirror of BoringSSL (grpc依赖)
https://boringssl.googlesource.com/boringssl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
664 lines
21 KiB
664 lines
21 KiB
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
|
* All rights reserved. |
|
* |
|
* This package is an SSL implementation written |
|
* by Eric Young (eay@cryptsoft.com). |
|
* The implementation was written so as to conform with Netscapes SSL. |
|
* |
|
* This library is free for commercial and non-commercial use as long as |
|
* the following conditions are aheared to. The following conditions |
|
* apply to all code found in this distribution, be it the RC4, RSA, |
|
* lhash, DES, etc., code; not just the SSL code. The SSL documentation |
|
* included with this distribution is covered by the same copyright terms |
|
* except that the holder is Tim Hudson (tjh@cryptsoft.com). |
|
* |
|
* Copyright remains Eric Young's, and as such any Copyright notices in |
|
* the code are not to be removed. |
|
* If this package is used in a product, Eric Young should be given attribution |
|
* as the author of the parts of the library used. |
|
* This can be in the form of a textual message at program startup or |
|
* in documentation (online or textual) provided with the package. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* 3. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* "This product includes cryptographic software written by |
|
* Eric Young (eay@cryptsoft.com)" |
|
* The word 'cryptographic' can be left out if the rouines from the library |
|
* being used are not cryptographic related :-). |
|
* 4. If you include any Windows specific code (or a derivative thereof) from |
|
* the apps directory (application code) you must include an acknowledgement: |
|
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
* SUCH DAMAGE. |
|
* |
|
* The licence and distribution terms for any publically available version or |
|
* derivative of this code cannot be changed. i.e. this code cannot simply be |
|
* copied and put under another distribution licence |
|
* [including the GNU Public Licence.] */ |
|
|
|
#include <openssl/asn1.h> |
|
|
|
#include <limits.h> |
|
#include <string.h> |
|
|
|
#include <openssl/asn1t.h> |
|
#include <openssl/mem.h> |
|
|
|
#include "../internal.h" |
|
|
|
|
|
static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, |
|
const ASN1_ITEM *it, int tag, int aclass); |
|
static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, |
|
int skcontlen, const ASN1_ITEM *item, |
|
int do_sort, int iclass); |
|
static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, |
|
const ASN1_TEMPLATE *tt, int tag, int aclass); |
|
static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, |
|
const ASN1_ITEM *it, int flags); |
|
|
|
/* |
|
* Top level i2d equivalents: the 'ndef' variant instructs the encoder to use |
|
* indefinite length constructed encoding, where appropriate |
|
*/ |
|
|
|
int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, |
|
const ASN1_ITEM *it) |
|
{ |
|
return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF); |
|
} |
|
|
|
int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) |
|
{ |
|
return asn1_item_flags_i2d(val, out, it, 0); |
|
} |
|
|
|
/* |
|
* Encode an ASN1 item, this is use by the standard 'i2d' function. 'out' |
|
* points to a buffer to output the data to. The new i2d has one additional |
|
* feature. If the output buffer is NULL (i.e. *out == NULL) then a buffer is |
|
* allocated and populated with the encoding. |
|
*/ |
|
|
|
static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, |
|
const ASN1_ITEM *it, int flags) |
|
{ |
|
if (out && !*out) { |
|
unsigned char *p, *buf; |
|
int len; |
|
len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags); |
|
if (len <= 0) |
|
return len; |
|
buf = OPENSSL_malloc(len); |
|
if (!buf) |
|
return -1; |
|
p = buf; |
|
ASN1_item_ex_i2d(&val, &p, it, -1, flags); |
|
*out = buf; |
|
return len; |
|
} |
|
|
|
return ASN1_item_ex_i2d(&val, out, it, -1, flags); |
|
} |
|
|
|
/* |
|
* Encode an item, taking care of IMPLICIT tagging (if any). This function |
|
* performs the normal item handling: it can be used in external types. |
|
*/ |
|
|
|
int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, |
|
const ASN1_ITEM *it, int tag, int aclass) |
|
{ |
|
const ASN1_TEMPLATE *tt = NULL; |
|
unsigned char *p = NULL; |
|
int i, seqcontlen, seqlen, ndef = 1; |
|
const ASN1_COMPAT_FUNCS *cf; |
|
const ASN1_EXTERN_FUNCS *ef; |
|
const ASN1_AUX *aux = it->funcs; |
|
ASN1_aux_cb *asn1_cb = 0; |
|
|
|
if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) |
|
return 0; |
|
|
|
if (aux && aux->asn1_cb) |
|
asn1_cb = aux->asn1_cb; |
|
|
|
switch (it->itype) { |
|
|
|
case ASN1_ITYPE_PRIMITIVE: |
|
if (it->templates) |
|
return asn1_template_ex_i2d(pval, out, it->templates, |
|
tag, aclass); |
|
return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); |
|
break; |
|
|
|
case ASN1_ITYPE_MSTRING: |
|
return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); |
|
|
|
case ASN1_ITYPE_CHOICE: |
|
if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) |
|
return 0; |
|
i = asn1_get_choice_selector(pval, it); |
|
if ((i >= 0) && (i < it->tcount)) { |
|
ASN1_VALUE **pchval; |
|
const ASN1_TEMPLATE *chtt; |
|
chtt = it->templates + i; |
|
pchval = asn1_get_field_ptr(pval, chtt); |
|
return asn1_template_ex_i2d(pchval, out, chtt, -1, aclass); |
|
} |
|
/* Fixme: error condition if selector out of range */ |
|
if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) |
|
return 0; |
|
break; |
|
|
|
case ASN1_ITYPE_EXTERN: |
|
/* If new style i2d it does all the work */ |
|
ef = it->funcs; |
|
return ef->asn1_ex_i2d(pval, out, it, tag, aclass); |
|
|
|
case ASN1_ITYPE_COMPAT: |
|
/* old style hackery... */ |
|
cf = it->funcs; |
|
if (out) |
|
p = *out; |
|
i = cf->asn1_i2d(*pval, out); |
|
/* |
|
* Fixup for IMPLICIT tag: note this messes up for tags > 30, but so |
|
* did the old code. Tags > 30 are very rare anyway. |
|
*/ |
|
if (out && (tag != -1)) |
|
*p = aclass | tag | (*p & V_ASN1_CONSTRUCTED); |
|
return i; |
|
|
|
case ASN1_ITYPE_NDEF_SEQUENCE: |
|
/* Use indefinite length constructed if requested */ |
|
if (aclass & ASN1_TFLG_NDEF) |
|
ndef = 2; |
|
OPENSSL_FALLTHROUGH; |
|
|
|
case ASN1_ITYPE_SEQUENCE: |
|
i = asn1_enc_restore(&seqcontlen, out, pval, it); |
|
/* An error occurred */ |
|
if (i < 0) |
|
return 0; |
|
/* We have a valid cached encoding... */ |
|
if (i > 0) |
|
return seqcontlen; |
|
/* Otherwise carry on */ |
|
seqcontlen = 0; |
|
/* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ |
|
if (tag == -1) { |
|
tag = V_ASN1_SEQUENCE; |
|
/* Retain any other flags in aclass */ |
|
aclass = (aclass & ~ASN1_TFLG_TAG_CLASS) |
|
| V_ASN1_UNIVERSAL; |
|
} |
|
if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) |
|
return 0; |
|
/* First work out sequence content length */ |
|
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { |
|
const ASN1_TEMPLATE *seqtt; |
|
ASN1_VALUE **pseqval; |
|
int tmplen; |
|
seqtt = asn1_do_adb(pval, tt, 1); |
|
if (!seqtt) |
|
return 0; |
|
pseqval = asn1_get_field_ptr(pval, seqtt); |
|
tmplen = asn1_template_ex_i2d(pseqval, NULL, seqtt, -1, aclass); |
|
if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen)) |
|
return -1; |
|
seqcontlen += tmplen; |
|
} |
|
|
|
seqlen = ASN1_object_size(ndef, seqcontlen, tag); |
|
if (!out || seqlen == -1) |
|
return seqlen; |
|
/* Output SEQUENCE header */ |
|
ASN1_put_object(out, ndef, seqcontlen, tag, aclass); |
|
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { |
|
const ASN1_TEMPLATE *seqtt; |
|
ASN1_VALUE **pseqval; |
|
seqtt = asn1_do_adb(pval, tt, 1); |
|
if (!seqtt) |
|
return 0; |
|
pseqval = asn1_get_field_ptr(pval, seqtt); |
|
/* FIXME: check for errors in enhanced version */ |
|
asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass); |
|
} |
|
if (ndef == 2) |
|
ASN1_put_eoc(out); |
|
if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) |
|
return 0; |
|
return seqlen; |
|
|
|
default: |
|
return 0; |
|
|
|
} |
|
return 0; |
|
} |
|
|
|
static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, |
|
const ASN1_TEMPLATE *tt, int tag, int iclass) |
|
{ |
|
int i, ret, flags, ttag, tclass, ndef; |
|
size_t j; |
|
flags = tt->flags; |
|
/* |
|
* Work out tag and class to use: tagging may come either from the |
|
* template or the arguments, not both because this would create |
|
* ambiguity. Additionally the iclass argument may contain some |
|
* additional flags which should be noted and passed down to other |
|
* levels. |
|
*/ |
|
if (flags & ASN1_TFLG_TAG_MASK) { |
|
/* Error if argument and template tagging */ |
|
if (tag != -1) |
|
/* FIXME: error code here */ |
|
return -1; |
|
/* Get tagging from template */ |
|
ttag = tt->tag; |
|
tclass = flags & ASN1_TFLG_TAG_CLASS; |
|
} else if (tag != -1) { |
|
/* No template tagging, get from arguments */ |
|
ttag = tag; |
|
tclass = iclass & ASN1_TFLG_TAG_CLASS; |
|
} else { |
|
ttag = -1; |
|
tclass = 0; |
|
} |
|
/* |
|
* Remove any class mask from iflag. |
|
*/ |
|
iclass &= ~ASN1_TFLG_TAG_CLASS; |
|
|
|
/* |
|
* At this point 'ttag' contains the outer tag to use, 'tclass' is the |
|
* class and iclass is any flags passed to this function. |
|
*/ |
|
|
|
/* if template and arguments require ndef, use it */ |
|
if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF)) |
|
ndef = 2; |
|
else |
|
ndef = 1; |
|
|
|
if (flags & ASN1_TFLG_SK_MASK) { |
|
/* SET OF, SEQUENCE OF */ |
|
STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; |
|
int isset, sktag, skaclass; |
|
int skcontlen, sklen; |
|
ASN1_VALUE *skitem; |
|
|
|
if (!*pval) |
|
return 0; |
|
|
|
if (flags & ASN1_TFLG_SET_OF) { |
|
isset = 1; |
|
/* 2 means we reorder */ |
|
if (flags & ASN1_TFLG_SEQUENCE_OF) |
|
isset = 2; |
|
} else |
|
isset = 0; |
|
|
|
/* |
|
* Work out inner tag value: if EXPLICIT or no tagging use underlying |
|
* type. |
|
*/ |
|
if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) { |
|
sktag = ttag; |
|
skaclass = tclass; |
|
} else { |
|
skaclass = V_ASN1_UNIVERSAL; |
|
if (isset) |
|
sktag = V_ASN1_SET; |
|
else |
|
sktag = V_ASN1_SEQUENCE; |
|
} |
|
|
|
/* Determine total length of items */ |
|
skcontlen = 0; |
|
for (j = 0; j < sk_ASN1_VALUE_num(sk); j++) { |
|
int tmplen; |
|
skitem = sk_ASN1_VALUE_value(sk, j); |
|
tmplen = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item), |
|
-1, iclass); |
|
if (tmplen == -1 || (skcontlen > INT_MAX - tmplen)) |
|
return -1; |
|
skcontlen += tmplen; |
|
} |
|
sklen = ASN1_object_size(ndef, skcontlen, sktag); |
|
if (sklen == -1) |
|
return -1; |
|
/* If EXPLICIT need length of surrounding tag */ |
|
if (flags & ASN1_TFLG_EXPTAG) |
|
ret = ASN1_object_size(ndef, sklen, ttag); |
|
else |
|
ret = sklen; |
|
|
|
if (!out || ret == -1) |
|
return ret; |
|
|
|
/* Now encode this lot... */ |
|
/* EXPLICIT tag */ |
|
if (flags & ASN1_TFLG_EXPTAG) |
|
ASN1_put_object(out, ndef, sklen, ttag, tclass); |
|
/* SET or SEQUENCE and IMPLICIT tag */ |
|
ASN1_put_object(out, ndef, skcontlen, sktag, skaclass); |
|
/* And the stuff itself */ |
|
asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), |
|
isset, iclass); |
|
if (ndef == 2) { |
|
ASN1_put_eoc(out); |
|
if (flags & ASN1_TFLG_EXPTAG) |
|
ASN1_put_eoc(out); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
if (flags & ASN1_TFLG_EXPTAG) { |
|
/* EXPLICIT tagging */ |
|
/* Find length of tagged item */ |
|
i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, iclass); |
|
if (!i) |
|
return 0; |
|
/* Find length of EXPLICIT tag */ |
|
ret = ASN1_object_size(ndef, i, ttag); |
|
if (out && ret != -1) { |
|
/* Output tag and item */ |
|
ASN1_put_object(out, ndef, i, ttag, tclass); |
|
ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, iclass); |
|
if (ndef == 2) |
|
ASN1_put_eoc(out); |
|
} |
|
return ret; |
|
} |
|
|
|
/* Either normal or IMPLICIT tagging: combine class and flags */ |
|
return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), |
|
ttag, tclass | iclass); |
|
|
|
} |
|
|
|
/* Temporary structure used to hold DER encoding of items for SET OF */ |
|
|
|
typedef struct { |
|
unsigned char *data; |
|
int length; |
|
ASN1_VALUE *field; |
|
} DER_ENC; |
|
|
|
static int der_cmp(const void *a, const void *b) |
|
{ |
|
const DER_ENC *d1 = a, *d2 = b; |
|
int cmplen, i; |
|
cmplen = (d1->length < d2->length) ? d1->length : d2->length; |
|
i = OPENSSL_memcmp(d1->data, d2->data, cmplen); |
|
if (i) |
|
return i; |
|
return d1->length - d2->length; |
|
} |
|
|
|
/* Output the content octets of SET OF or SEQUENCE OF */ |
|
|
|
static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, |
|
int skcontlen, const ASN1_ITEM *item, |
|
int do_sort, int iclass) |
|
{ |
|
size_t i; |
|
ASN1_VALUE *skitem; |
|
unsigned char *tmpdat = NULL, *p = NULL; |
|
DER_ENC *derlst = NULL, *tder; |
|
if (do_sort) { |
|
/* Don't need to sort less than 2 items */ |
|
if (sk_ASN1_VALUE_num(sk) < 2) |
|
do_sort = 0; |
|
else { |
|
derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) |
|
* sizeof(*derlst)); |
|
if (!derlst) |
|
return 0; |
|
tmpdat = OPENSSL_malloc(skcontlen); |
|
if (!tmpdat) { |
|
OPENSSL_free(derlst); |
|
return 0; |
|
} |
|
} |
|
} |
|
/* If not sorting just output each item */ |
|
if (!do_sort) { |
|
for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) { |
|
skitem = sk_ASN1_VALUE_value(sk, i); |
|
ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); |
|
} |
|
return 1; |
|
} |
|
p = tmpdat; |
|
|
|
/* Doing sort: build up a list of each member's DER encoding */ |
|
for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { |
|
skitem = sk_ASN1_VALUE_value(sk, i); |
|
tder->data = p; |
|
tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass); |
|
tder->field = skitem; |
|
} |
|
|
|
/* Now sort them */ |
|
qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); |
|
/* Output sorted DER encoding */ |
|
p = *out; |
|
for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { |
|
OPENSSL_memcpy(p, tder->data, tder->length); |
|
p += tder->length; |
|
} |
|
*out = p; |
|
/* If do_sort is 2 then reorder the STACK */ |
|
if (do_sort == 2) { |
|
for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) |
|
(void)sk_ASN1_VALUE_set(sk, i, tder->field); |
|
} |
|
OPENSSL_free(derlst); |
|
OPENSSL_free(tmpdat); |
|
return 1; |
|
} |
|
|
|
static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, |
|
const ASN1_ITEM *it, int tag, int aclass) |
|
{ |
|
int len; |
|
int utype; |
|
int usetag; |
|
int ndef = 0; |
|
|
|
utype = it->utype; |
|
|
|
/* |
|
* Get length of content octets and maybe find out the underlying type. |
|
*/ |
|
|
|
len = asn1_ex_i2c(pval, NULL, &utype, it); |
|
|
|
/* |
|
* If SEQUENCE, SET or OTHER then header is included in pseudo content |
|
* octets so don't include tag+length. We need to check here because the |
|
* call to asn1_ex_i2c() could change utype. |
|
*/ |
|
if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || |
|
(utype == V_ASN1_OTHER)) |
|
usetag = 0; |
|
else |
|
usetag = 1; |
|
|
|
/* -1 means omit type */ |
|
|
|
if (len == -1) |
|
return 0; |
|
|
|
/* -2 return is special meaning use ndef */ |
|
if (len == -2) { |
|
ndef = 2; |
|
len = 0; |
|
} |
|
|
|
/* If not implicitly tagged get tag from underlying type */ |
|
if (tag == -1) |
|
tag = utype; |
|
|
|
/* Output tag+length followed by content octets */ |
|
if (out) { |
|
if (usetag) |
|
ASN1_put_object(out, ndef, len, tag, aclass); |
|
asn1_ex_i2c(pval, *out, &utype, it); |
|
if (ndef) |
|
ASN1_put_eoc(out); |
|
else |
|
*out += len; |
|
} |
|
|
|
if (usetag) |
|
return ASN1_object_size(ndef, len, tag); |
|
return len; |
|
} |
|
|
|
/* Produce content octets from a structure */ |
|
|
|
int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, |
|
const ASN1_ITEM *it) |
|
{ |
|
ASN1_BOOLEAN *tbool = NULL; |
|
ASN1_STRING *strtmp; |
|
ASN1_OBJECT *otmp; |
|
int utype; |
|
const unsigned char *cont; |
|
unsigned char c; |
|
int len; |
|
const ASN1_PRIMITIVE_FUNCS *pf; |
|
pf = it->funcs; |
|
if (pf && pf->prim_i2c) |
|
return pf->prim_i2c(pval, cout, putype, it); |
|
|
|
/* Should type be omitted? */ |
|
if ((it->itype != ASN1_ITYPE_PRIMITIVE) |
|
|| (it->utype != V_ASN1_BOOLEAN)) { |
|
if (!*pval) |
|
return -1; |
|
} |
|
|
|
if (it->itype == ASN1_ITYPE_MSTRING) { |
|
/* If MSTRING type set the underlying type */ |
|
strtmp = (ASN1_STRING *)*pval; |
|
utype = strtmp->type; |
|
*putype = utype; |
|
} else if (it->utype == V_ASN1_ANY) { |
|
/* If ANY set type and pointer to value */ |
|
ASN1_TYPE *typ; |
|
typ = (ASN1_TYPE *)*pval; |
|
utype = typ->type; |
|
*putype = utype; |
|
pval = &typ->value.asn1_value; |
|
} else |
|
utype = *putype; |
|
|
|
switch (utype) { |
|
case V_ASN1_OBJECT: |
|
otmp = (ASN1_OBJECT *)*pval; |
|
cont = otmp->data; |
|
len = otmp->length; |
|
if (cont == NULL || len == 0) |
|
return -1; |
|
break; |
|
|
|
case V_ASN1_NULL: |
|
cont = NULL; |
|
len = 0; |
|
break; |
|
|
|
case V_ASN1_BOOLEAN: |
|
tbool = (ASN1_BOOLEAN *)pval; |
|
if (*tbool == -1) |
|
return -1; |
|
if (it->utype != V_ASN1_ANY) { |
|
/* |
|
* Default handling if value == size field then omit |
|
*/ |
|
if (*tbool && (it->size > 0)) |
|
return -1; |
|
if (!*tbool && !it->size) |
|
return -1; |
|
} |
|
c = (unsigned char)*tbool; |
|
cont = &c; |
|
len = 1; |
|
break; |
|
|
|
case V_ASN1_BIT_STRING: |
|
return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, |
|
cout ? &cout : NULL); |
|
break; |
|
|
|
case V_ASN1_INTEGER: |
|
case V_ASN1_ENUMERATED: |
|
/* |
|
* These are all have the same content format as ASN1_INTEGER |
|
*/ |
|
return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL); |
|
break; |
|
|
|
case V_ASN1_OCTET_STRING: |
|
case V_ASN1_NUMERICSTRING: |
|
case V_ASN1_PRINTABLESTRING: |
|
case V_ASN1_T61STRING: |
|
case V_ASN1_VIDEOTEXSTRING: |
|
case V_ASN1_IA5STRING: |
|
case V_ASN1_UTCTIME: |
|
case V_ASN1_GENERALIZEDTIME: |
|
case V_ASN1_GRAPHICSTRING: |
|
case V_ASN1_VISIBLESTRING: |
|
case V_ASN1_GENERALSTRING: |
|
case V_ASN1_UNIVERSALSTRING: |
|
case V_ASN1_BMPSTRING: |
|
case V_ASN1_UTF8STRING: |
|
case V_ASN1_SEQUENCE: |
|
case V_ASN1_SET: |
|
default: |
|
/* All based on ASN1_STRING and handled the same */ |
|
strtmp = (ASN1_STRING *)*pval; |
|
/* Special handling for NDEF */ |
|
if ((it->size == ASN1_TFLG_NDEF) |
|
&& (strtmp->flags & ASN1_STRING_FLAG_NDEF)) { |
|
if (cout) { |
|
strtmp->data = cout; |
|
strtmp->length = 0; |
|
} |
|
/* Special return code */ |
|
return -2; |
|
} |
|
cont = strtmp->data; |
|
len = strtmp->length; |
|
|
|
break; |
|
|
|
} |
|
if (cout && len) |
|
OPENSSL_memcpy(cout, cont, len); |
|
return len; |
|
}
|
|
|