openssl/crypto/asn1/a_strnid.c
Rich Salz 852c2ed260 In OpenSSL builds, declare STACK for datatypes ...
... and only *define* them in the source files that need them.
Use DEFINE_OR_DECLARE which is set appropriately for internal builds
and not non-deprecated builds.

Deprecate stack-of-block

Better documentation

Move some ASN1 struct typedefs to types.h

Update ParseC to handle this.  Most of all, ParseC needed to be more
consistent.  The handlers are "recursive", in so far that they are called
again and again until they terminate, which depends entirely on what the
"massager" returns.  There's a comment at the beginning of ParseC that
explains how that works. {Richard Levtte}

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/10669)
2020-04-24 16:42:46 +02:00

225 lines
6.1 KiB
C

/*
* Copyright 1999-2018 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>
DEFINE_STACK_OF(ASN1_STRING_TABLE)
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 (strncmp(p, "MASK:", 5) == 0) {
if (p[5] == '\0')
return 0;
mask = strtoul(p + 5, &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) {
ASN1err(ASN1_F_STABLE_GET, 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) {
ASN1err(ASN1_F_ASN1_STRING_TABLE_ADD, 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);
}