| // Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     https://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | #include <openssl/asn1.h> | 
 |  | 
 | #include <string.h> | 
 |  | 
 | #include <openssl/asn1t.h> | 
 | #include <openssl/err.h> | 
 | #include <openssl/mem.h> | 
 | #include <openssl/obj.h> | 
 |  | 
 | #include "../internal.h" | 
 | #include "internal.h" | 
 |  | 
 |  | 
 | static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); | 
 | static int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); | 
 | static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); | 
 | static int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it); | 
 | static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); | 
 |  | 
 | ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it) { | 
 |   ASN1_VALUE *ret = NULL; | 
 |   if (ASN1_item_ex_new(&ret, it) > 0) { | 
 |     return ret; | 
 |   } | 
 |   return NULL; | 
 | } | 
 |  | 
 | // Allocate an ASN1 structure | 
 |  | 
 | int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it) { | 
 |   const ASN1_TEMPLATE *tt = NULL; | 
 |   const ASN1_EXTERN_FUNCS *ef; | 
 |   ASN1_VALUE **pseqval; | 
 |   int i; | 
 |  | 
 |   switch (it->itype) { | 
 |     case ASN1_ITYPE_EXTERN: | 
 |       ef = reinterpret_cast<const ASN1_EXTERN_FUNCS *>(it->funcs); | 
 |       if (ef && ef->asn1_ex_new) { | 
 |         if (!ef->asn1_ex_new(pval, it)) { | 
 |           goto memerr; | 
 |         } | 
 |       } | 
 |       break; | 
 |  | 
 |     case ASN1_ITYPE_PRIMITIVE: | 
 |       if (it->templates) { | 
 |         if (!ASN1_template_new(pval, it->templates)) { | 
 |           goto memerr; | 
 |         } | 
 |       } else if (!ASN1_primitive_new(pval, it)) { | 
 |         goto memerr; | 
 |       } | 
 |       break; | 
 |  | 
 |     case ASN1_ITYPE_MSTRING: | 
 |       if (!ASN1_primitive_new(pval, it)) { | 
 |         goto memerr; | 
 |       } | 
 |       break; | 
 |  | 
 |     case ASN1_ITYPE_CHOICE: { | 
 |       const ASN1_AUX *aux = reinterpret_cast<const ASN1_AUX *>(it->funcs); | 
 |       ASN1_aux_cb *asn1_cb = aux != NULL ? aux->asn1_cb : NULL; | 
 |       if (asn1_cb) { | 
 |         i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL); | 
 |         if (!i) { | 
 |           goto auxerr; | 
 |         } | 
 |         if (i == 2) { | 
 |           return 1; | 
 |         } | 
 |       } | 
 |       *pval = reinterpret_cast<ASN1_VALUE *>(OPENSSL_zalloc(it->size)); | 
 |       if (!*pval) { | 
 |         goto memerr; | 
 |       } | 
 |       asn1_set_choice_selector(pval, -1, it); | 
 |       if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL)) { | 
 |         goto auxerr2; | 
 |       } | 
 |       break; | 
 |     } | 
 |  | 
 |     case ASN1_ITYPE_SEQUENCE: { | 
 |       const ASN1_AUX *aux = reinterpret_cast<const ASN1_AUX *>(it->funcs); | 
 |       ASN1_aux_cb *asn1_cb = aux != NULL ? aux->asn1_cb : NULL; | 
 |       if (asn1_cb) { | 
 |         i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL); | 
 |         if (!i) { | 
 |           goto auxerr; | 
 |         } | 
 |         if (i == 2) { | 
 |           return 1; | 
 |         } | 
 |       } | 
 |       *pval = reinterpret_cast<ASN1_VALUE *>(OPENSSL_zalloc(it->size)); | 
 |       if (!*pval) { | 
 |         goto memerr; | 
 |       } | 
 |       asn1_refcount_set_one(pval, it); | 
 |       asn1_enc_init(pval, it); | 
 |       for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { | 
 |         pseqval = asn1_get_field_ptr(pval, tt); | 
 |         if (!ASN1_template_new(pseqval, tt)) { | 
 |           goto memerr2; | 
 |         } | 
 |       } | 
 |       if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL)) { | 
 |         goto auxerr2; | 
 |       } | 
 |       break; | 
 |     } | 
 |   } | 
 |   return 1; | 
 |  | 
 | memerr2: | 
 |   ASN1_item_ex_free(pval, it); | 
 | memerr: | 
 |   return 0; | 
 |  | 
 | auxerr2: | 
 |   ASN1_item_ex_free(pval, it); | 
 | auxerr: | 
 |   OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR); | 
 |   return 0; | 
 | } | 
 |  | 
 | static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it) { | 
 |   switch (it->itype) { | 
 |     case ASN1_ITYPE_EXTERN: | 
 |       *pval = NULL; | 
 |       break; | 
 |  | 
 |     case ASN1_ITYPE_PRIMITIVE: | 
 |       if (it->templates) { | 
 |         asn1_template_clear(pval, it->templates); | 
 |       } else { | 
 |         asn1_primitive_clear(pval, it); | 
 |       } | 
 |       break; | 
 |  | 
 |     case ASN1_ITYPE_MSTRING: | 
 |       asn1_primitive_clear(pval, it); | 
 |       break; | 
 |  | 
 |     case ASN1_ITYPE_CHOICE: | 
 |     case ASN1_ITYPE_SEQUENCE: | 
 |       *pval = NULL; | 
 |       break; | 
 |   } | 
 | } | 
 |  | 
 | static int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) { | 
 |   const ASN1_ITEM *it = ASN1_ITEM_ptr(tt->item); | 
 |   int ret; | 
 |   if (tt->flags & ASN1_TFLG_OPTIONAL) { | 
 |     asn1_template_clear(pval, tt); | 
 |     return 1; | 
 |   } | 
 |   // If ANY DEFINED BY nothing to do | 
 |  | 
 |   if (tt->flags & ASN1_TFLG_ADB_MASK) { | 
 |     *pval = NULL; | 
 |     return 1; | 
 |   } | 
 |   // If SET OF or SEQUENCE OF, its a STACK | 
 |   if (tt->flags & ASN1_TFLG_SK_MASK) { | 
 |     STACK_OF(ASN1_VALUE) *skval; | 
 |     skval = sk_ASN1_VALUE_new_null(); | 
 |     if (!skval) { | 
 |       ret = 0; | 
 |       goto done; | 
 |     } | 
 |     *pval = (ASN1_VALUE *)skval; | 
 |     ret = 1; | 
 |     goto done; | 
 |   } | 
 |   // Otherwise pass it back to the item routine | 
 |   ret = ASN1_item_ex_new(pval, it); | 
 | done: | 
 |   return ret; | 
 | } | 
 |  | 
 | static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) { | 
 |   // If ADB or STACK just NULL the field | 
 |   if (tt->flags & (ASN1_TFLG_ADB_MASK | ASN1_TFLG_SK_MASK)) { | 
 |     *pval = NULL; | 
 |   } else { | 
 |     asn1_item_clear(pval, ASN1_ITEM_ptr(tt->item)); | 
 |   } | 
 | } | 
 |  | 
 | // NB: could probably combine most of the real XXX_new() behaviour and junk | 
 | // all the old functions. | 
 |  | 
 | static int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it) { | 
 |   if (!it) { | 
 |     return 0; | 
 |   } | 
 |  | 
 |   // Historically, |it->funcs| for primitive types contained an | 
 |   // |ASN1_PRIMITIVE_FUNCS| table of calbacks. | 
 |   assert(it->funcs == NULL); | 
 |  | 
 |   int utype; | 
 |   if (it->itype == ASN1_ITYPE_MSTRING) { | 
 |     utype = -1; | 
 |   } else { | 
 |     utype = it->utype; | 
 |   } | 
 |   switch (utype) { | 
 |     case V_ASN1_OBJECT: | 
 |       *pval = (ASN1_VALUE *)OBJ_get_undef(); | 
 |       return 1; | 
 |  | 
 |     case V_ASN1_BOOLEAN: | 
 |       *(ASN1_BOOLEAN *)pval = (ASN1_BOOLEAN)it->size; | 
 |       return 1; | 
 |  | 
 |     case V_ASN1_NULL: | 
 |       *pval = (ASN1_VALUE *)1; | 
 |       return 1; | 
 |  | 
 |     case V_ASN1_ANY: { | 
 |       ASN1_TYPE *typ = | 
 |           reinterpret_cast<ASN1_TYPE *>(OPENSSL_malloc(sizeof(ASN1_TYPE))); | 
 |       if (!typ) { | 
 |         return 0; | 
 |       } | 
 |       typ->value.ptr = NULL; | 
 |       typ->type = -1; | 
 |       *pval = (ASN1_VALUE *)typ; | 
 |       break; | 
 |     } | 
 |  | 
 |     default: | 
 |       *pval = (ASN1_VALUE *)ASN1_STRING_type_new(utype); | 
 |       break; | 
 |   } | 
 |   if (*pval) { | 
 |     return 1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it) { | 
 |   int utype; | 
 |   // Historically, |it->funcs| for primitive types contained an | 
 |   // |ASN1_PRIMITIVE_FUNCS| table of calbacks. | 
 |   assert(it == NULL || it->funcs == NULL); | 
 |   if (!it || (it->itype == ASN1_ITYPE_MSTRING)) { | 
 |     utype = -1; | 
 |   } else { | 
 |     utype = it->utype; | 
 |   } | 
 |   if (utype == V_ASN1_BOOLEAN) { | 
 |     *(ASN1_BOOLEAN *)pval = (ASN1_BOOLEAN)it->size; | 
 |   } else { | 
 |     *pval = NULL; | 
 |   } | 
 | } |