/* * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (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 */ #include #include #include #include #include #include #include #include #include #include "../internal.h" #include "internal.h" // Utility functions for manipulating fields and offsets // Add 'offset' to 'addr' #define offset2ptr(addr, offset) (void *)(((char *)(addr)) + (offset)) // Given an ASN1_ITEM CHOICE type return the selector value int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it) { int *sel = reinterpret_cast(offset2ptr(*pval, it->utype)); return *sel; } // Given an ASN1_ITEM CHOICE type set the selector value, return old value. int asn1_set_choice_selector(ASN1_VALUE **pval, int value, const ASN1_ITEM *it) { int *sel, ret; sel = reinterpret_cast(offset2ptr(*pval, it->utype)); ret = *sel; *sel = value; return ret; } static CRYPTO_refcount_t *asn1_get_references(ASN1_VALUE **pval, const ASN1_ITEM *it) { if (it->itype != ASN1_ITYPE_SEQUENCE) { return NULL; } const ASN1_AUX *aux = reinterpret_cast(it->funcs); if (!aux || !(aux->flags & ASN1_AFLG_REFCOUNT)) { return NULL; } return reinterpret_cast( offset2ptr(*pval, aux->ref_offset)); } void asn1_refcount_set_one(ASN1_VALUE **pval, const ASN1_ITEM *it) { CRYPTO_refcount_t *references = asn1_get_references(pval, it); if (references != NULL) { *references = 1; } } int asn1_refcount_dec_and_test_zero(ASN1_VALUE **pval, const ASN1_ITEM *it) { CRYPTO_refcount_t *references = asn1_get_references(pval, it); if (references != NULL) { return CRYPTO_refcount_dec_and_test_zero(references); } return 1; } static ASN1_ENCODING *asn1_get_enc_ptr(ASN1_VALUE **pval, const ASN1_ITEM *it) { assert(it->itype == ASN1_ITYPE_SEQUENCE); const ASN1_AUX *aux; if (!pval || !*pval) { return NULL; } aux = reinterpret_cast(it->funcs); if (!aux || !(aux->flags & ASN1_AFLG_ENCODING)) { return NULL; } return reinterpret_cast(offset2ptr(*pval, aux->enc_offset)); } void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it) { ASN1_ENCODING *enc = asn1_get_enc_ptr(pval, it); if (enc) { enc->enc = NULL; enc->len = 0; enc->buf = NULL; } } void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it) { ASN1_ENCODING *enc = asn1_get_enc_ptr(pval, it); if (enc) { asn1_encoding_clear(enc); } } int asn1_enc_save(ASN1_VALUE **pval, const uint8_t *in, size_t in_len, const ASN1_ITEM *it, CRYPTO_BUFFER *buf) { ASN1_ENCODING *enc; enc = asn1_get_enc_ptr(pval, it); if (!enc) { return 1; } asn1_encoding_clear(enc); if (buf != NULL) { assert(CRYPTO_BUFFER_data(buf) <= in && in + in_len <= CRYPTO_BUFFER_data(buf) + CRYPTO_BUFFER_len(buf)); CRYPTO_BUFFER_up_ref(buf); enc->buf = buf; enc->enc = (uint8_t *)in; } else { enc->enc = reinterpret_cast(OPENSSL_memdup(in, in_len)); if (!enc->enc) { return 0; } } enc->len = in_len; return 1; } void asn1_encoding_clear(ASN1_ENCODING *enc) { if (enc->buf != NULL) { CRYPTO_BUFFER_free(enc->buf); } else { OPENSSL_free(enc->enc); } enc->enc = NULL; enc->len = 0; enc->buf = NULL; } int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, const ASN1_ITEM *it) { ASN1_ENCODING *enc = asn1_get_enc_ptr(pval, it); if (!enc || enc->len == 0) { return 0; } if (out) { OPENSSL_memcpy(*out, enc->enc, enc->len); *out += enc->len; } if (len) { *len = enc->len; } return 1; } // Given an ASN1_TEMPLATE get a pointer to a field ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) { ASN1_VALUE **pvaltmp = reinterpret_cast(offset2ptr(*pval, tt->offset)); // NOTE for BOOLEAN types the field is just a plain int so we can't return // int **, so settle for (int *). return pvaltmp; } // Handle ANY DEFINED BY template, find the selector, look up the relevant // ASN1_TEMPLATE in the table and return it. const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, int nullerr) { const ASN1_ADB *adb; const ASN1_ADB_TABLE *atbl; ASN1_VALUE **sfld; int i; if (!(tt->flags & ASN1_TFLG_ADB_MASK)) { return tt; } // Else ANY DEFINED BY ... get the table adb = ASN1_ADB_ptr(tt->item); // Get the selector field sfld = reinterpret_cast(offset2ptr(*pval, adb->offset)); // Check if NULL int selector; if (*sfld == NULL) { if (!adb->null_tt) { goto err; } return adb->null_tt; } // Convert type to a NID: // NB: don't check for NID_undef here because it // might be a legitimate value in the table assert(tt->flags & ASN1_TFLG_ADB_OID); selector = OBJ_obj2nid((ASN1_OBJECT *)*sfld); // Try to find matching entry in table Maybe should check application types // first to allow application override? Might also be useful to have a flag // which indicates table is sorted and we can do a binary search. For now // stick to a linear search. for (atbl = adb->tbl, i = 0; i < adb->tblcount; i++, atbl++) { if (atbl->value == selector) { return &atbl->tt; } } // FIXME: need to search application table too // No match, return default type if (!adb->default_tt) { goto err; } return adb->default_tt; err: // FIXME: should log the value or OID of unsupported type if (nullerr) { OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE); } return NULL; }