diff options
Diffstat (limited to 'crypto/asn1/tasn_enc.c')
-rw-r--r-- | crypto/asn1/tasn_enc.c | 168 |
1 files changed, 96 insertions, 72 deletions
diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c index bcc96337bca4..fb2e040c7c56 100644 --- a/crypto/asn1/tasn_enc.c +++ b/crypto/asn1/tasn_enc.c @@ -1,7 +1,7 @@ /* - * Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -16,16 +16,17 @@ #include "crypto/asn1.h" #include "asn1_local.h" -static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, +static int asn1_i2d_ex_primitive(const 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, +static int asn1_set_seq_out(STACK_OF(const_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, +static int asn1_template_ex_i2d(const 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, +static int asn1_item_flags_i2d(const ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it, int flags); -static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, +static int asn1_ex_i2c(const ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_ITEM *it); /* @@ -33,13 +34,13 @@ static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, * indefinite length constructed encoding, where appropriate */ -int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, +int ASN1_item_ndef_i2d(const 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) +int ASN1_item_i2d(const ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) { return asn1_item_flags_i2d(val, out, it, 0); } @@ -51,10 +52,10 @@ int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) * allocated and populated with the encoding. */ -static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, +static int asn1_item_flags_i2d(const ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it, int flags) { - if (out && !*out) { + if (out != NULL && *out == NULL) { unsigned char *p, *buf; int len; @@ -62,7 +63,7 @@ static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, if (len <= 0) return len; if ((buf = OPENSSL_malloc(len)) == NULL) { - ASN1err(ASN1_F_ASN1_ITEM_FLAGS_I2D, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); return -1; } p = buf; @@ -79,20 +80,22 @@ static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, * performs the normal item handling: it can be used in external types. */ -int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, +int ASN1_item_ex_i2d(const ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass) { const ASN1_TEMPLATE *tt = NULL; int i, seqcontlen, seqlen, ndef = 1; const ASN1_EXTERN_FUNCS *ef; const ASN1_AUX *aux = it->funcs; - ASN1_aux_cb *asn1_cb = 0; + ASN1_aux_const_cb *asn1_cb = NULL; - if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) + if ((it->itype != ASN1_ITYPE_PRIMITIVE) && *pval == NULL) return 0; - if (aux && aux->asn1_cb) - asn1_cb = aux->asn1_cb; + if (aux != NULL) { + asn1_cb = ((aux->flags & ASN1_AFLG_CONST_CB) != 0) ? aux->asn1_const_cb + : (ASN1_aux_const_cb *)aux->asn1_cb; /* backward compatibility */ + } switch (it->itype) { @@ -108,7 +111,7 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, * if tag != -1, then this looks like an error in the template. */ if (tag != -1) { - ASN1err(ASN1_F_ASN1_ITEM_EX_I2D, ASN1_R_BAD_TEMPLATE); + ERR_raise(ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE); return -1; } return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); @@ -119,17 +122,17 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, * if tag != -1, then this looks like an error in the template. */ if (tag != -1) { - ASN1err(ASN1_F_ASN1_ITEM_EX_I2D, ASN1_R_BAD_TEMPLATE); + ERR_raise(ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE); return -1; } if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) return 0; - i = asn1_get_choice_selector(pval, it); + i = ossl_asn1_get_choice_selector_const(pval, it); if ((i >= 0) && (i < it->tcount)) { - ASN1_VALUE **pchval; + const ASN1_VALUE **pchval; const ASN1_TEMPLATE *chtt; chtt = it->templates + i; - pchval = asn1_get_field_ptr(pval, chtt); + pchval = ossl_asn1_get_const_field_ptr(pval, chtt); return asn1_template_ex_i2d(pchval, out, chtt, -1, aclass); } /* Fixme: error condition if selector out of range */ @@ -149,7 +152,7 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, /* fall through */ case ASN1_ITYPE_SEQUENCE: - i = asn1_enc_restore(&seqcontlen, out, pval, it); + i = ossl_asn1_enc_restore(&seqcontlen, out, pval, it); /* An error occurred */ if (i < 0) return 0; @@ -170,12 +173,12 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, /* First work out sequence content length */ for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { const ASN1_TEMPLATE *seqtt; - ASN1_VALUE **pseqval; + const ASN1_VALUE **pseqval; int tmplen; - seqtt = asn1_do_adb(pval, tt, 1); + seqtt = ossl_asn1_do_adb(*pval, tt, 1); if (!seqtt) return 0; - pseqval = asn1_get_field_ptr(pval, seqtt); + pseqval = ossl_asn1_get_const_field_ptr(pval, seqtt); tmplen = asn1_template_ex_i2d(pseqval, NULL, seqtt, -1, aclass); if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen)) return -1; @@ -189,11 +192,11 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, 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); + const ASN1_VALUE **pseqval; + seqtt = ossl_asn1_do_adb(*pval, tt, 1); if (!seqtt) return 0; - pseqval = asn1_get_field_ptr(pval, seqtt); + pseqval = ossl_asn1_get_const_field_ptr(pval, seqtt); /* FIXME: check for errors in enhanced version */ asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass); } @@ -210,12 +213,12 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, return 0; } -static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, +static int asn1_template_ex_i2d(const ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt, int tag, int iclass) { - int i, ret, flags, ttag, tclass, ndef; - ASN1_VALUE *tval; - flags = tt->flags; + const int flags = tt->flags; + int i, ret, ttag, tclass, ndef, len; + const ASN1_VALUE *tval; /* * If field is embedded then val needs fixing so it is a pointer to @@ -266,12 +269,12 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, if (flags & ASN1_TFLG_SK_MASK) { /* SET OF, SEQUENCE OF */ - STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; + STACK_OF(const_ASN1_VALUE) *sk = (STACK_OF(const_ASN1_VALUE) *)*pval; int isset, sktag, skaclass; int skcontlen, sklen; - ASN1_VALUE *skitem; + const ASN1_VALUE *skitem; - if (!*pval) + if (*pval == NULL) return 0; if (flags & ASN1_TFLG_SET_OF) { @@ -299,14 +302,17 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, /* Determine total length of items */ skcontlen = 0; - for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) { - int tmplen; - skitem = sk_ASN1_VALUE_value(sk, i); - tmplen = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item), - -1, iclass); - if (tmplen == -1 || (skcontlen > INT_MAX - tmplen)) + for (i = 0; i < sk_const_ASN1_VALUE_num(sk); i++) { + skitem = sk_const_ASN1_VALUE_value(sk, i); + len = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item), + -1, iclass); + if (len == -1 || (skcontlen > INT_MAX - len)) return -1; - skcontlen += tmplen; + if (len == 0 && (tt->flags & ASN1_TFLG_OPTIONAL) == 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT); + return -1; + } + skcontlen += len; } sklen = ASN1_object_size(ndef, skcontlen, sktag); if (sklen == -1) @@ -342,8 +348,13 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, /* EXPLICIT tagging */ /* Find length of tagged item */ i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, iclass); - if (!i) + if (i == 0) { + if ((tt->flags & ASN1_TFLG_OPTIONAL) == 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT); + return -1; + } return 0; + } /* Find length of EXPLICIT tag */ ret = ASN1_object_size(ndef, i, ttag); if (out && ret != -1) { @@ -357,9 +368,13 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, } /* Either normal or IMPLICIT tagging: combine class and flags */ - return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), - ttag, tclass | iclass); - + len = ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), + ttag, tclass | iclass); + if (len == 0 && (tt->flags & ASN1_TFLG_OPTIONAL) == 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT); + return -1; + } + return len; } /* Temporary structure used to hold DER encoding of items for SET OF */ @@ -367,7 +382,7 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, typedef struct { unsigned char *data; int length; - ASN1_VALUE *field; + const ASN1_VALUE *field; } DER_ENC; static int der_cmp(const void *a, const void *b) @@ -383,34 +398,38 @@ static int der_cmp(const void *a, const void *b) /* Output the content octets of SET OF or SEQUENCE OF */ -static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, +static int asn1_set_seq_out(STACK_OF(const_ASN1_VALUE) *sk, + unsigned char **out, int skcontlen, const ASN1_ITEM *item, int do_sort, int iclass) { - int i; - ASN1_VALUE *skitem; + int i, ret = 0; + const 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) + if (sk_const_ASN1_VALUE_num(sk) < 2) do_sort = 0; else { - derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) + derlst = OPENSSL_malloc(sk_const_ASN1_VALUE_num(sk) * sizeof(*derlst)); - if (derlst == NULL) + if (derlst == NULL) { + ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); return 0; + } tmpdat = OPENSSL_malloc(skcontlen); if (tmpdat == NULL) { - OPENSSL_free(derlst); - return 0; + ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); + goto err; } } } /* 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); + for (i = 0; i < sk_const_ASN1_VALUE_num(sk); i++) { + skitem = sk_const_ASN1_VALUE_value(sk, i); ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); } return 1; @@ -418,33 +437,35 @@ static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, 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); + for (i = 0, tder = derlst; i < sk_const_ASN1_VALUE_num(sk); i++, tder++) { + skitem = sk_const_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); + qsort(derlst, sk_const_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++) { + for (i = 0, tder = derlst; i < sk_const_ASN1_VALUE_num(sk); i++, tder++) { 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); + for (i = 0, tder = derlst; i < sk_const_ASN1_VALUE_num(sk); i++, tder++) + (void)sk_const_ASN1_VALUE_set(sk, i, tder->field); } + ret = 1; +err: OPENSSL_free(derlst); OPENSSL_free(tmpdat); - return 1; + return ret; } -static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, +static int asn1_i2d_ex_primitive(const ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass) { int len; @@ -504,7 +525,7 @@ static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, /* Produce content octets from a structure */ -static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, +static int asn1_ex_i2c(const ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_ITEM *it) { ASN1_BOOLEAN *tbool = NULL; @@ -522,7 +543,7 @@ static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, /* Should type be omitted? */ if ((it->itype != ASN1_ITYPE_PRIMITIVE) || (it->utype != V_ASN1_BOOLEAN)) { - if (!*pval) + if (*pval == NULL) return -1; } @@ -537,7 +558,7 @@ static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, typ = (ASN1_TYPE *)*pval; utype = typ->type; *putype = utype; - pval = &typ->value.asn1_value; + pval = (const ASN1_VALUE **)&typ->value.asn1_value; /* actually is const */ } else utype = *putype; @@ -550,6 +571,9 @@ static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, return -1; break; + case V_ASN1_UNDEF: + return -2; + case V_ASN1_NULL: cont = NULL; len = 0; @@ -574,15 +598,15 @@ static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, break; case V_ASN1_BIT_STRING: - return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, - cout ? &cout : NULL); + return ossl_i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, + cout ? &cout : NULL); 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); + return ossl_i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL); case V_ASN1_OCTET_STRING: case V_ASN1_NUMERICSTRING: |