Commit a1df06b3 authored by Pauli's avatar Pauli
Browse files

This has been added to avoid the situation where some host ctype.h functions


return true for characters > 127.  I.e. they are allowing extended ASCII
characters through which then cause problems.  E.g. marking superscript '2' as
a number then causes the common (ch - '0') conversion to number to fail
miserably.  Likewise letters with diacritical marks can also cause problems.

If a non-ASCII character set is being used (currently only EBCDIC), it is
adjusted for.

The implementation uses a single table with a bit for each of the defined
classes.  These functions accept an int argument and fail for
values out of range or for characters outside of the ASCII set.  They will
work for both signed and unsigned character inputs.

Reviewed-by: default avatarAndy Polyakov <appro@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/4102)
parent 00dfbaad
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@

#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include "internal/cryptlib.h"
#include <openssl/asn1.h>
#include "asn1_locl.h"
+8 −60
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@
 */

#include <stdio.h>
#include <ctype.h>
#include "internal/ctype.h"
#include "internal/cryptlib.h"
#include <openssl/asn1.h>

@@ -22,8 +22,6 @@ static int cpy_asc(unsigned long value, void *arg);
static int cpy_bmp(unsigned long value, void *arg);
static int cpy_univ(unsigned long value, void *arg);
static int cpy_utf8(unsigned long value, void *arg);
static int is_numeric(unsigned long value);
static int is_printable(unsigned long value);

/*
 * These functions take a string in UTF8, ASCII or multibyte form and a mask
@@ -271,13 +269,15 @@ static int out_utf8(unsigned long value, void *arg)

static int type_str(unsigned long value, void *arg)
{
    unsigned long types;
    types = *((unsigned long *)arg);
    if ((types & B_ASN1_NUMERICSTRING) && !is_numeric(value))
    unsigned long types = *((unsigned long *)arg);
    const int native = value > INT_MAX ? INT_MAX : ossl_fromascii(value);

    if ((types & B_ASN1_NUMERICSTRING) && !(ossl_isdigit(native)
                                            || native == ' '))
        types &= ~B_ASN1_NUMERICSTRING;
    if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value))
    if ((types & B_ASN1_PRINTABLESTRING) && !ossl_isasn1print(native))
        types &= ~B_ASN1_PRINTABLESTRING;
    if ((types & B_ASN1_IA5STRING) && (value > 127))
    if ((types & B_ASN1_IA5STRING) && !ossl_isascii(native))
        types &= ~B_ASN1_IA5STRING;
    if ((types & B_ASN1_T61STRING) && (value > 0xff))
        types &= ~B_ASN1_T61STRING;
@@ -341,55 +341,3 @@ static int cpy_utf8(unsigned long value, void *arg)
    *p += ret;
    return 1;
}

/* Return 1 if the character is permitted in a PrintableString */
static int is_printable(unsigned long value)
{
    int ch;
    if (value > 0x7f)
        return 0;
    ch = (int)value;
    /*
     * Note: we can't use 'isalnum' because certain accented characters may
     * count as alphanumeric in some environments.
     */
#ifndef CHARSET_EBCDIC
    if ((ch >= 'a') && (ch <= 'z'))
        return 1;
    if ((ch >= 'A') && (ch <= 'Z'))
        return 1;
    if ((ch >= '0') && (ch <= '9'))
        return 1;
    if ((ch == ' ') || strchr("'()+,-./:=?", ch))
        return 1;
#else                           /* CHARSET_EBCDIC */
    if ((ch >= os_toascii['a']) && (ch <= os_toascii['z']))
        return 1;
    if ((ch >= os_toascii['A']) && (ch <= os_toascii['Z']))
        return 1;
    if ((ch >= os_toascii['0']) && (ch <= os_toascii['9']))
        return 1;
    if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch]))
        return 1;
#endif                          /* CHARSET_EBCDIC */
    return 0;
}

/* Return 1 if the character is a digit or space */
static int is_numeric(unsigned long value)
{
    int ch;
    if (value > 0x7f)
        return 0;
    ch = (int)value;
#ifndef CHARSET_EBCDIC
    if (!isdigit(ch) && ch != ' ')
        return 0;
#else
    if (ch > os_toascii['9'])
        return 0;
    if (ch < os_toascii['0'] && ch != os_toascii[' '])
        return 0;
#endif
    return 1;
}
+3 −3
Original line number Diff line number Diff line
/*
 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 1995-2017 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
@@ -9,7 +9,7 @@

#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include "internal/ctype.h"
#include "internal/cryptlib.h"
#include <openssl/buffer.h>
#include <openssl/asn1.h>
@@ -85,7 +85,7 @@ int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
            c = *(p++);
            if ((c == ' ') || (c == '.'))
                break;
            if (!isdigit(c)) {
            if (!ossl_isdigit(c)) {
                ASN1err(ASN1_F_A2D_ASN1_OBJECT, ASN1_R_INVALID_DIGIT);
                goto err;
            }
+4 −18
Original line number Diff line number Diff line
/*
 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 1995-2017 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
@@ -8,7 +8,7 @@
 */

#include <stdio.h>
#include <ctype.h>
#include "internal/ctype.h"
#include "internal/cryptlib.h"
#include <openssl/asn1.h>

@@ -25,24 +25,10 @@ int ASN1_PRINTABLE_type(const unsigned char *s, int len)

    while ((*s) && (len-- != 0)) {
        c = *(s++);
#ifndef CHARSET_EBCDIC
        if (!(((c >= 'a') && (c <= 'z')) ||
              ((c >= 'A') && (c <= 'Z')) ||
              ((c >= '0') && (c <= '9')) ||
              (c == ' ') || (c == '\'') ||
              (c == '(') || (c == ')') ||
              (c == '+') || (c == ',') ||
              (c == '-') || (c == '.') ||
              (c == '/') || (c == ':') || (c == '=') || (c == '?')))
        if (!ossl_isasn1print(c))
            ia5 = 1;
        if (c & 0x80)
        if (!ossl_isascii(c))
            t61 = 1;
#else
        if (!isalnum(c) && (c != ' ') && strchr("'()+,-./:=?", c) == NULL)
            ia5 = 1;
        if (os_toascii[c] & 0x80)
            t61 = 1;
#endif
    }
    if (t61)
        return (V_ASN1_T61STRING);
+0 −1
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@
 */

#include <stdio.h>
#include <ctype.h>
#include "internal/cryptlib.h"
#include <openssl/asn1.h>
#include <openssl/objects.h>
Loading