| /* |
| * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved. |
| * |
| * 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 |
| */ |
| |
| #include <stdio.h> |
| #include "internal/cryptlib.h" |
| #include <openssl/asn1.h> |
| #include <openssl/objects.h> |
| |
| static STACK_OF(ASN1_STRING_TABLE) *stable = NULL; |
| static void st_free(ASN1_STRING_TABLE *tbl); |
| static int sk_table_cmp(const ASN1_STRING_TABLE *const *a, |
| const ASN1_STRING_TABLE *const *b); |
| |
| /* |
| * This is the global mask for the mbstring functions: this is use to mask |
| * out certain types (such as BMPString and UTF8String) because certain |
| * software (e.g. Netscape) has problems with them. |
| */ |
| |
| static unsigned long global_mask = B_ASN1_UTF8STRING; |
| |
| void ASN1_STRING_set_default_mask(unsigned long mask) |
| { |
| global_mask = mask; |
| } |
| |
| unsigned long ASN1_STRING_get_default_mask(void) |
| { |
| return global_mask; |
| } |
| |
| /*- |
| * This function sets the default to various "flavours" of configuration. |
| * based on an ASCII string. Currently this is: |
| * MASK:XXXX : a numerical mask value. |
| * nobmp : Don't use BMPStrings (just Printable, T61). |
| * pkix : PKIX recommendation in RFC2459. |
| * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004). |
| * default: the default value, Printable, T61, BMP. |
| */ |
| |
| int ASN1_STRING_set_default_mask_asc(const char *p) |
| { |
| unsigned long mask; |
| char *end; |
| |
| if (CHECK_AND_SKIP_PREFIX(p, "MASK:")) { |
| if (*p == '\0') |
| return 0; |
| mask = strtoul(p, &end, 0); |
| if (*end) |
| return 0; |
| } else if (strcmp(p, "nombstr") == 0) |
| mask = ~((unsigned long)(B_ASN1_BMPSTRING | B_ASN1_UTF8STRING)); |
| else if (strcmp(p, "pkix") == 0) |
| mask = ~((unsigned long)B_ASN1_T61STRING); |
| else if (strcmp(p, "utf8only") == 0) |
| mask = B_ASN1_UTF8STRING; |
| else if (strcmp(p, "default") == 0) |
| mask = 0xFFFFFFFFL; |
| else |
| return 0; |
| ASN1_STRING_set_default_mask(mask); |
| return 1; |
| } |
| |
| /* |
| * The following function generates an ASN1_STRING based on limits in a |
| * table. Frequently the types and length of an ASN1_STRING are restricted by |
| * a corresponding OID. For example certificates and certificate requests. |
| */ |
| |
| ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, |
| const unsigned char *in, int inlen, |
| int inform, int nid) |
| { |
| ASN1_STRING_TABLE *tbl; |
| ASN1_STRING *str = NULL; |
| unsigned long mask; |
| int ret; |
| |
| if (out == NULL) |
| out = &str; |
| tbl = ASN1_STRING_TABLE_get(nid); |
| if (tbl != NULL) { |
| mask = tbl->mask; |
| if (!(tbl->flags & STABLE_NO_MASK)) |
| mask &= global_mask; |
| ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask, |
| tbl->minsize, tbl->maxsize); |
| } else { |
| ret = ASN1_mbstring_copy(out, in, inlen, inform, |
| DIRSTRING_TYPE & global_mask); |
| } |
| if (ret <= 0) |
| return NULL; |
| return *out; |
| } |
| |
| /* |
| * Now the tables and helper functions for the string table: |
| */ |
| |
| #include "tbl_standard.h" |
| |
| static int sk_table_cmp(const ASN1_STRING_TABLE *const *a, |
| const ASN1_STRING_TABLE *const *b) |
| { |
| return (*a)->nid - (*b)->nid; |
| } |
| |
| DECLARE_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table); |
| |
| static int table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b) |
| { |
| return a->nid - b->nid; |
| } |
| |
| IMPLEMENT_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table); |
| |
| ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid) |
| { |
| int idx; |
| ASN1_STRING_TABLE fnd; |
| |
| /* "stable" can be impacted by config, so load the config file first */ |
| OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); |
| |
| fnd.nid = nid; |
| if (stable) { |
| idx = sk_ASN1_STRING_TABLE_find(stable, &fnd); |
| if (idx >= 0) |
| return sk_ASN1_STRING_TABLE_value(stable, idx); |
| } |
| return OBJ_bsearch_table(&fnd, tbl_standard, OSSL_NELEM(tbl_standard)); |
| } |
| |
| /* |
| * Return a string table pointer which can be modified: either directly from |
| * table or a copy of an internal value added to the table. |
| */ |
| |
| static ASN1_STRING_TABLE *stable_get(int nid) |
| { |
| ASN1_STRING_TABLE *tmp, *rv; |
| |
| /* Always need a string table so allocate one if NULL */ |
| if (stable == NULL) { |
| stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp); |
| if (stable == NULL) |
| return NULL; |
| } |
| tmp = ASN1_STRING_TABLE_get(nid); |
| if (tmp != NULL && tmp->flags & STABLE_FLAGS_MALLOC) |
| return tmp; |
| if ((rv = OPENSSL_zalloc(sizeof(*rv))) == NULL) { |
| ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| if (!sk_ASN1_STRING_TABLE_push(stable, rv)) { |
| OPENSSL_free(rv); |
| return NULL; |
| } |
| if (tmp != NULL) { |
| rv->nid = tmp->nid; |
| rv->minsize = tmp->minsize; |
| rv->maxsize = tmp->maxsize; |
| rv->mask = tmp->mask; |
| rv->flags = tmp->flags | STABLE_FLAGS_MALLOC; |
| } else { |
| rv->nid = nid; |
| rv->minsize = -1; |
| rv->maxsize = -1; |
| rv->flags = STABLE_FLAGS_MALLOC; |
| } |
| return rv; |
| } |
| |
| int ASN1_STRING_TABLE_add(int nid, |
| long minsize, long maxsize, unsigned long mask, |
| unsigned long flags) |
| { |
| ASN1_STRING_TABLE *tmp; |
| |
| tmp = stable_get(nid); |
| if (tmp == NULL) { |
| ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); |
| return 0; |
| } |
| if (minsize >= 0) |
| tmp->minsize = minsize; |
| if (maxsize >= 0) |
| tmp->maxsize = maxsize; |
| if (mask) |
| tmp->mask = mask; |
| if (flags) |
| tmp->flags = STABLE_FLAGS_MALLOC | flags; |
| return 1; |
| } |
| |
| void ASN1_STRING_TABLE_cleanup(void) |
| { |
| STACK_OF(ASN1_STRING_TABLE) *tmp; |
| |
| tmp = stable; |
| if (tmp == NULL) |
| return; |
| stable = NULL; |
| sk_ASN1_STRING_TABLE_pop_free(tmp, st_free); |
| } |
| |
| static void st_free(ASN1_STRING_TABLE *tbl) |
| { |
| if (tbl->flags & STABLE_FLAGS_MALLOC) |
| OPENSSL_free(tbl); |
| } |