static int DecodeCertExtensions(DecodedCert* cert)
/*
 *  Processing the Certificate Extensions. This does not modify the current
 *  index. It is works starting with the recorded extensions pointer.
 */
{
    int ret = 0;
    word32 idx = 0;
    int sz = cert->extensionsSz;
    const byte* input = cert->extensions;
    int length;
    word32 oid;
    byte critical = 0;
    byte criticalFail = 0;
    byte tag = 0;

    WOLFSSL_ENTER("DecodeCertExtensions");

    if (input == NULL || sz == 0)
        return BAD_FUNC_ARG;

#ifdef WOLFSSL_CERT_REQ
    if (!cert->isCSR)
#endif
    { /* Not included in CSR */
        if (GetASNTag(input, &idx, &tag, sz) < 0) {
            return ASN_PARSE_E;
        }

        if (tag != ASN_EXTENSIONS) {
            WOLFSSL_MSG("\tfail: should be an EXTENSIONS");
            return ASN_PARSE_E;
        }

        if (GetLength(input, &idx, &length, sz) < 0) {
            WOLFSSL_MSG("\tfail: invalid length");
            return ASN_PARSE_E;
        }
    }

    if (GetSequence(input, &idx, &length, sz) < 0) {
        WOLFSSL_MSG("\tfail: should be a SEQUENCE (1)");
        return ASN_PARSE_E;
    }

    while (idx < (word32)sz) {
        word32 localIdx;

        if (GetSequence(input, &idx, &length, sz) < 0) {
            WOLFSSL_MSG("\tfail: should be a SEQUENCE");
            return ASN_PARSE_E;
        }

        oid = 0;
        if ((ret = GetObjectId(input, &idx, &oid, oidCertExtType, sz)) < 0) {
            WOLFSSL_MSG("\tfail: OBJECT ID");
            return ret;
        }

        /* check for critical flag */
        critical = 0;
        if ((idx + 1) > (word32)sz) {
            WOLFSSL_MSG("\tfail: malformed buffer");
            return BUFFER_E;
        }

        localIdx = idx;
        if (GetASNTag(input, &localIdx, &tag, sz) == 0) {
            if (tag == ASN_BOOLEAN) {
                ret = GetBoolean(input, &idx, sz);
                if (ret < 0) {
                    WOLFSSL_MSG("\tfail: critical boolean");
                    return ret;
                }

                critical = (byte)ret;
            }
        }

        /* process the extension based on the OID */
        ret = GetOctetString(input, &idx, &length, sz);
        if (ret < 0) {
            WOLFSSL_MSG("\tfail: bad OCTET STRING");
            return ret;
        }

        switch (oid) {
            case BASIC_CA_OID:
                VERIFY_AND_SET_OID(cert->extBasicConstSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extBasicConstCrit = critical;
                #endif
                if (DecodeBasicCaConstraint(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case CRL_DIST_OID:
                VERIFY_AND_SET_OID(cert->extCRLdistSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extCRLdistCrit = critical;
                #endif
                if (DecodeCrlDist(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case AUTH_INFO_OID:
                VERIFY_AND_SET_OID(cert->extAuthInfoSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extAuthInfoCrit = critical;
                #endif
                if (DecodeAuthInfo(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case ALT_NAMES_OID:
                VERIFY_AND_SET_OID(cert->extSubjAltNameSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extSubjAltNameCrit = critical;
                #endif
                ret = DecodeAltNames(&input[idx], length, cert);
                if (ret < 0)
                    return ret;
                break;

            case AUTH_KEY_OID:
                VERIFY_AND_SET_OID(cert->extAuthKeyIdSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extAuthKeyIdCrit = critical;
                #endif
                #ifndef WOLFSSL_ALLOW_CRIT_SKID
                    /* This check is added due to RFC 5280 section 4.2.1.1
                     * stating that conforming CA's must mark this extension
                     * as non-critical. When parsing extensions check that
                     * certificate was made in compliance with this. */
                    if (critical) {
                        WOLFSSL_MSG("Critical Auth Key ID is not allowed");
                        WOLFSSL_MSG("Use macro WOLFSSL_ALLOW_CRIT_SKID if wanted");
                        return ASN_CRIT_EXT_E;
                    }
                #endif
                if (DecodeAuthKeyId(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case SUBJ_KEY_OID:
                VERIFY_AND_SET_OID(cert->extSubjKeyIdSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extSubjKeyIdCrit = critical;
                #endif
                #ifndef WOLFSSL_ALLOW_CRIT_SKID
                    /* This check is added due to RFC 5280 section 4.2.1.2
                     * stating that conforming CA's must mark this extension
                     * as non-critical. When parsing extensions check that
                     * certificate was made in compliance with this. */
                    if (critical) {
                        WOLFSSL_MSG("Critical Subject Key ID is not allowed");
                        WOLFSSL_MSG("Use macro WOLFSSL_ALLOW_CRIT_SKID if wanted");
                        return ASN_CRIT_EXT_E;
                    }
                #endif

                if (DecodeSubjKeyId(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case CERT_POLICY_OID:
                #if defined(WOLFSSL_SEP) || defined(WOLFSSL_QT)
                    VERIFY_AND_SET_OID(cert->extCertPolicySet);
                    #if defined(OPENSSL_EXTRA) || \
                        defined(OPENSSL_EXTRA_X509_SMALL)
                        cert->extCertPolicyCrit = critical;
                    #endif
                #endif
                #if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT) || \
                    defined(WOLFSSL_QT)
                    if (DecodeCertPolicy(&input[idx], length, cert) < 0) {
                        return ASN_PARSE_E;
                    }
                #else
                    WOLFSSL_MSG("Certificate Policy extension not supported yet.");
                #endif
                break;

            case KEY_USAGE_OID:
                VERIFY_AND_SET_OID(cert->extKeyUsageSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extKeyUsageCrit = critical;
                #endif
                if (DecodeKeyUsage(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case EXT_KEY_USAGE_OID:
                VERIFY_AND_SET_OID(cert->extExtKeyUsageSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extExtKeyUsageCrit = critical;
                #endif
                if (DecodeExtKeyUsage(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            #ifndef IGNORE_NAME_CONSTRAINTS
            case NAME_CONS_OID:
            #ifndef WOLFSSL_NO_ASN_STRICT
                /* Verify RFC 5280 Sec 4.2.1.10 rule:
                    "The name constraints extension,
                    which MUST be used only in a CA certificate" */
                if (!cert->isCA) {
                    WOLFSSL_MSG("Name constraints allowed only for CA certs");
                    return ASN_NAME_INVALID_E;
                }
            #endif
                VERIFY_AND_SET_OID(cert->extNameConstraintSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extNameConstraintCrit = critical;
                #endif
                if (DecodeNameConstraints(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;
            #endif /* IGNORE_NAME_CONSTRAINTS */

            case INHIBIT_ANY_OID:
                VERIFY_AND_SET_OID(cert->inhibitAnyOidSet);
                WOLFSSL_MSG("Inhibit anyPolicy extension not supported yet.");
                break;

       #ifndef IGNORE_NETSCAPE_CERT_TYPE
            case NETSCAPE_CT_OID:
                WOLFSSL_MSG("Netscape certificate type extension not supported "
                            "yet.");
                if (CheckBitString(input, &idx, &length, idx + length, 0,
                                                                    NULL) < 0) {
                    return ASN_PARSE_E;
                }
                break;
        #endif
        #ifdef HAVE_OCSP
            case OCSP_NOCHECK_OID:
                VERIFY_AND_SET_OID(cert->ocspNoCheckSet);
                ret = GetASNNull(input, &idx, sz);
                length = 0; /* idx is already incremented, reset length to 0 */
                if (ret != 0)
                    return ASN_PARSE_E;
                break;
        #endif
            case POLICY_CONST_OID:
                VERIFY_AND_SET_OID(cert->extPolicyConstSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extPolicyConstCrit = critical;
                #endif
                if (DecodePolicyConstraints(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;
            default:
            #ifndef WOLFSSL_NO_ASN_STRICT
                /* While it is a failure to not support critical extensions,
                 * still parse the certificate ignoring the unsupported
                 * extension to allow caller to accept it with the verify
                 * callback. */
                if (critical)
                    criticalFail = 1;
            #endif
            break;
        }
        idx += length;
    }

    return criticalFail ? ASN_CRIT_EXT_E : 0;
}
static int DecodeCertExtensions(DecodedCert* cert)
 
{
    int ret = 0;
    word32 idx = 0;
    int sz = cert->extensionsSz;
    const byte* input = cert->extensions;
    int length;
    word32 oid;
    byte critical = 0;
    byte criticalFail = 0;
    byte tag = 0;

    WOLFSSL_ENTER("DecodeCertExtensions");

    if (input == NULL || sz == 0)
        return BAD_FUNC_ARG;

#ifdef WOLFSSL_CERT_REQ
    if (!cert->isCSR)
#endif
    {  
        if (GetASNTag(input, &idx, &tag, sz) < 0) {
            return ASN_PARSE_E;
        }

        if (tag != ASN_EXTENSIONS) {
            WOLFSSL_MSG("\tfail: should be an EXTENSIONS");
            return ASN_PARSE_E;
        }

        if (GetLength(input, &idx, &length, sz) < 0) {
            WOLFSSL_MSG("\tfail: invalid length");
            return ASN_PARSE_E;
        }
    }

    if (GetSequence(input, &idx, &length, sz) < 0) {
        WOLFSSL_MSG("\tfail: should be a SEQUENCE (1)");
        return ASN_PARSE_E;
    }

    while (idx < (word32)sz) {
        word32 localIdx;

        if (GetSequence(input, &idx, &length, sz) < 0) {
            WOLFSSL_MSG("\tfail: should be a SEQUENCE");
            return ASN_PARSE_E;
        }

        oid = 0;
        if ((ret = GetObjectId(input, &idx, &oid, oidCertExtType, sz)) < 0) {
            WOLFSSL_MSG("\tfail: OBJECT ID");
            return ret;
        }

         
        critical = 0;
        if ((idx + 1) > (word32)sz) {
            WOLFSSL_MSG("\tfail: malformed buffer");
            return BUFFER_E;
        }

        localIdx = idx;
        if (GetASNTag(input, &localIdx, &tag, sz) == 0) {
            if (tag == ASN_BOOLEAN) {
                ret = GetBoolean(input, &idx, sz);
                if (ret < 0) {
                    WOLFSSL_MSG("\tfail: critical boolean");
                    return ret;
                }

                critical = (byte)ret;
            }
        }

         
        ret = GetOctetString(input, &idx, &length, sz);
        if (ret < 0) {
            WOLFSSL_MSG("\tfail: bad OCTET STRING");
            return ret;
        }

        switch (oid) {
            case BASIC_CA_OID:
                VERIFY_AND_SET_OID(cert->extBasicConstSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extBasicConstCrit = critical;
                #endif
                if (DecodeBasicCaConstraint(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case CRL_DIST_OID:
                VERIFY_AND_SET_OID(cert->extCRLdistSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extCRLdistCrit = critical;
                #endif
                if (DecodeCrlDist(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case AUTH_INFO_OID:
                VERIFY_AND_SET_OID(cert->extAuthInfoSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extAuthInfoCrit = critical;
                #endif
                if (DecodeAuthInfo(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case ALT_NAMES_OID:
                VERIFY_AND_SET_OID(cert->extSubjAltNameSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extSubjAltNameCrit = critical;
                #endif
                ret = DecodeAltNames(&input[idx], length, cert);
                if (ret < 0)
                    return ret;
                break;

            case AUTH_KEY_OID:
                VERIFY_AND_SET_OID(cert->extAuthKeyIdSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extAuthKeyIdCrit = critical;
                #endif
                #ifndef WOLFSSL_ALLOW_CRIT_SKID
                     
                    if (critical) {
                        WOLFSSL_MSG("Critical Auth Key ID is not allowed");
                        WOLFSSL_MSG("Use macro WOLFSSL_ALLOW_CRIT_SKID if wanted");
                        return ASN_CRIT_EXT_E;
                    }
                #endif
                if (DecodeAuthKeyId(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case SUBJ_KEY_OID:
                VERIFY_AND_SET_OID(cert->extSubjKeyIdSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extSubjKeyIdCrit = critical;
                #endif
                #ifndef WOLFSSL_ALLOW_CRIT_SKID
                     
                    if (critical) {
                        WOLFSSL_MSG("Critical Subject Key ID is not allowed");
                        WOLFSSL_MSG("Use macro WOLFSSL_ALLOW_CRIT_SKID if wanted");
                        return ASN_CRIT_EXT_E;
                    }
                #endif

                if (DecodeSubjKeyId(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case CERT_POLICY_OID:
                #if defined(WOLFSSL_SEP) || defined(WOLFSSL_QT)
                    VERIFY_AND_SET_OID(cert->extCertPolicySet);
                    #if defined(OPENSSL_EXTRA) || \
                        defined(OPENSSL_EXTRA_X509_SMALL)
                        cert->extCertPolicyCrit = critical;
                    #endif
                #endif
                #if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT) || \
                    defined(WOLFSSL_QT)
                    if (DecodeCertPolicy(&input[idx], length, cert) < 0) {
                        return ASN_PARSE_E;
                    }
                #else
                    WOLFSSL_MSG("Certificate Policy extension not supported yet.");
                #endif
                break;

            case KEY_USAGE_OID:
                VERIFY_AND_SET_OID(cert->extKeyUsageSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extKeyUsageCrit = critical;
                #endif
                if (DecodeKeyUsage(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            case EXT_KEY_USAGE_OID:
                VERIFY_AND_SET_OID(cert->extExtKeyUsageSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extExtKeyUsageCrit = critical;
                #endif
                if (DecodeExtKeyUsage(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;

            #ifndef IGNORE_NAME_CONSTRAINTS
            case NAME_CONS_OID:
            #ifndef WOLFSSL_NO_ASN_STRICT
                 
                if (!cert->isCA) {
                    WOLFSSL_MSG("Name constraints allowed only for CA certs");
                    return ASN_NAME_INVALID_E;
                }
            #endif
                VERIFY_AND_SET_OID(cert->extNameConstraintSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extNameConstraintCrit = critical;
                #endif
                if (DecodeNameConstraints(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;
            #endif  

            case INHIBIT_ANY_OID:
                VERIFY_AND_SET_OID(cert->inhibitAnyOidSet);
                WOLFSSL_MSG("Inhibit anyPolicy extension not supported yet.");
                break;

       #ifndef IGNORE_NETSCAPE_CERT_TYPE
            case NETSCAPE_CT_OID:
                WOLFSSL_MSG("Netscape certificate type extension not supported "
                            "yet.");
                if (CheckBitString(input, &idx, &length, idx + length, 0,
                                                                    NULL) < 0) {
                    return ASN_PARSE_E;
                }
                break;
        #endif
        #ifdef HAVE_OCSP
            case OCSP_NOCHECK_OID:
                VERIFY_AND_SET_OID(cert->ocspNoCheckSet);
                ret = GetASNNull(input, &idx, sz);
                length = 0;  
                if (ret != 0)
                    return ASN_PARSE_E;
                break;
        #endif
            case POLICY_CONST_OID:
                VERIFY_AND_SET_OID(cert->extPolicyConstSet);
                #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
                    cert->extPolicyConstCrit = critical;
                #endif
                if (DecodePolicyConstraints(&input[idx], length, cert) < 0)
                    return ASN_PARSE_E;
                break;
            default:
            #ifndef WOLFSSL_NO_ASN_STRICT
                 
                if (critical)
                    criticalFail = 1;
            #endif
            break;
        }
        idx += length;
    }

    return criticalFail ? ASN_CRIT_EXT_E : 0;
}