This has been added to avoid the situation where some host ctype.h functions
authorPauli <paul.dale@oracle.com>
Sun, 20 Aug 2017 21:19:17 +0000 (07:19 +1000)
committerPauli <paul.dale@oracle.com>
Mon, 21 Aug 2017 23:45:25 +0000 (09:45 +1000)
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: Andy Polyakov <appro@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/4102)

34 files changed:
crypto/asn1/a_gentm.c
crypto/asn1/a_mbstr.c
crypto/asn1/a_object.c
crypto/asn1/a_print.c
crypto/asn1/a_strnid.c
crypto/asn1/a_time.c
crypto/asn1/a_utctm.c
crypto/asn1/asn_mime.c
crypto/asn1/asn_moid.c
crypto/asn1/asn_mstbl.c
crypto/asn1/f_int.c
crypto/asn1/f_string.c
crypto/bio/b_addr.c
crypto/bio/b_print.c
crypto/bn/bn_print.c
crypto/build.info
crypto/ctype.c [new file with mode: 0644]
crypto/evp/evp_cnf.c
crypto/include/internal/ctype.h [new file with mode: 0644]
crypto/o_str.c
crypto/objects/obj_dat.c
crypto/ocsp/ocsp_ht.c
crypto/pem/pem_lib.c
crypto/pkcs7/pk7_mime.c
crypto/store/loader_file.c
crypto/store/store_register.c
crypto/x509/x509_cmp.c
crypto/x509/x509_vfy.c
crypto/x509/x_name.c
crypto/x509v3/v3_conf.c
crypto/x509v3/v3_utl.c
test/build.info
test/ctype_internal_test.c [new file with mode: 0644]
test/recipes/02-test_internal_ctype.t [new file with mode: 0644]

index 4e2e815d271680f12c538669ce1b4bed943b7a30..d3878d6e57fe4731d083747a024f8acd0cb9fbf7 100644 (file)
@@ -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"
index e644fe0542d786412f75dda773b862f0b9e566ff..949fe6c1611ac37a64a36ae03995da7fac1fd383 100644 (file)
@@ -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;
-}
index 5ae56a24ea8657be8170a5f00651e44651ab9fce..566d8b352caf893e739245d4e38550cbd0cfdf70 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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;
             }
index 1aafe7c839e6c5ac305b299c11e8d8fae2f9bf2e..ed72b519266783f2872ea18f06757fd7e2bd1da1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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);
index 04c77eb45276935c577908627829644acbf3b966..a7d6b0e3df2e3db680f2f02f2ee13f57c402ee1b 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <stdio.h>
-#include <ctype.h>
 #include "internal/cryptlib.h"
 #include <openssl/asn1.h>
 #include <openssl/objects.h>
index 507292b76e16c093670a7579008a0e1a43214547..cb19e8024aa7886b73948cfd1c2037a7ebff9532 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <stdio.h>
 #include <time.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include "internal/cryptlib.h"
 #include <openssl/asn1t.h>
 #include "asn1_locl.h"
@@ -124,14 +124,14 @@ int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
             i++;
             break;
         }
-        if (!isdigit(a[o]))
+        if (!ossl_isdigit(a[o]))
             goto err;
         n = a[o] - '0';
         /* incomplete 2-digital number */
         if (++o == l)
             goto err;
 
-        if (!isdigit(a[o]))
+        if (!ossl_isdigit(a[o]))
             goto err;
         n = (n * 10) + a[o] - '0';
         /* no more bytes to read, but we haven't seen time-zone yet */
@@ -192,7 +192,7 @@ int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
         if (++o == l)
             goto err;
         i = o;
-        while ((o < l) && isdigit(a[o]))
+        while ((o < l) && ossl_isdigit(a[o]))
             o++;
         /* Must have at least one digit after decimal point */
         if (i == o)
@@ -223,11 +223,11 @@ int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
         if (o + 4 != l)
             goto err;
         for (i = end; i < end + 2; i++) {
-            if (!isdigit(a[o]))
+            if (!ossl_isdigit(a[o]))
                 goto err;
             n = a[o] - '0';
             o++;
-            if (!isdigit(a[o]))
+            if (!ossl_isdigit(a[o]))
                 goto err;
             n = (n * 10) + a[o] - '0';
             i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i;
@@ -489,7 +489,7 @@ int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
         if (tm->length > 15 && v[14] == '.') {
             f = &v[14];
             f_len = 1;
-            while (14 + f_len < l && isdigit(f[f_len]))
+            while (14 + f_len < l && ossl_isdigit(f[f_len]))
                 ++f_len;
         }
 
index b88aa4218e11ffa7b01fff090da3c1995adbb5e7..b224991aa3df1ee06e3d5e53ce5a9dfd25c75a18 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <stdio.h>
 #include <time.h>
-#include <ctype.h>
 #include "internal/cryptlib.h"
 #include <openssl/asn1.h>
 #include "asn1_locl.h"
index d7ec801b1e779948f98cd4660402f5a085b475ab..01638da127884719ce8f74f904a8d1ed042e16d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2008-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/rand.h>
 #include <openssl/x509.h>
@@ -634,7 +634,7 @@ static STACK_OF(MIME_HEADER) *mime_parse_hdr(BIO *bio)
         return NULL;
     while ((len = BIO_gets(bio, linebuf, MAX_SMLEN)) > 0) {
         /* If whitespace at line start then continuation line */
-        if (mhdr && isspace((unsigned char)linebuf[0]))
+        if (mhdr && ossl_isspace(linebuf[0]))
             state = MIME_NAME;
         else
             state = MIME_START;
@@ -758,7 +758,7 @@ static char *strip_start(char *name)
             /* Else null string */
             return NULL;
         }
-        if (!isspace((unsigned char)c))
+        if (!ossl_isspace(c))
             return p;
     }
     return NULL;
@@ -779,7 +779,7 @@ static char *strip_end(char *name)
             *p = 0;
             return name;
         }
-        if (isspace((unsigned char)c))
+        if (ossl_isspace(c))
             *p = 0;
         else
             return name;
@@ -791,29 +791,18 @@ static MIME_HEADER *mime_hdr_new(const char *name, const char *value)
 {
     MIME_HEADER *mhdr = NULL;
     char *tmpname = NULL, *tmpval = NULL, *p;
-    int c;
 
     if (name) {
         if ((tmpname = OPENSSL_strdup(name)) == NULL)
             return NULL;
-        for (p = tmpname; *p; p++) {
-            c = (unsigned char)*p;
-            if (isupper(c)) {
-                c = tolower(c);
-                *p = c;
-            }
-        }
+        for (p = tmpname; *p; p++)
+            *p = ossl_tolower(*p);
     }
     if (value) {
         if ((tmpval = OPENSSL_strdup(value)) == NULL)
             goto err;
-        for (p = tmpval; *p; p++) {
-            c = (unsigned char)*p;
-            if (isupper(c)) {
-                c = tolower(c);
-                *p = c;
-            }
-        }
+        for (p = tmpval; *p; p++)
+            *p = ossl_tolower(*p);
     }
     mhdr = OPENSSL_malloc(sizeof(*mhdr));
     if (mhdr == NULL)
@@ -834,19 +823,14 @@ static MIME_HEADER *mime_hdr_new(const char *name, const char *value)
 static int mime_hdr_addparam(MIME_HEADER *mhdr, const char *name, const char *value)
 {
     char *tmpname = NULL, *tmpval = NULL, *p;
-    int c;
     MIME_PARAM *mparam = NULL;
+
     if (name) {
         tmpname = OPENSSL_strdup(name);
         if (!tmpname)
             goto err;
-        for (p = tmpname; *p; p++) {
-            c = (unsigned char)*p;
-            if (isupper(c)) {
-                c = tolower(c);
-                *p = c;
-            }
-        }
+        for (p = tmpname; *p; p++)
+            *p = ossl_tolower(*p);
     }
     if (value) {
         tmpval = OPENSSL_strdup(value);
index 8176b7600832a8ef81026592b09d99ae180b7bb0..ed8517c372c5708851194196149106c444d63b68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2002-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 <openssl/crypto.h>
 #include "internal/cryptlib.h"
 #include <openssl/conf.h>
@@ -72,7 +72,7 @@ static int do_create(const char *value, const char *name)
         ostr = p + 1;
         if (!*ostr)
             return 0;
-        while (isspace((unsigned char)*ostr))
+        while (ossl_isspace(*ostr))
             ostr++;
     }
 
@@ -83,10 +83,10 @@ static int do_create(const char *value, const char *name)
 
     if (p) {
         ln = value;
-        while (isspace((unsigned char)*ln))
+        while (ossl_isspace(*ln))
             ln++;
         p--;
-        while (isspace((unsigned char)*p)) {
+        while (ossl_isspace(*p)) {
             if (p == ln)
                 return 0;
             p--;
index 8260939002a70c15be853cb1a81d41279260ea74..ddcbcd07fe6ef71765e6fde34fcc46a1f0411c2f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2012-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,6 @@
  */
 
 #include <stdio.h>
-#include <ctype.h>
 #include <openssl/crypto.h>
 #include "internal/cryptlib.h"
 #include <openssl/conf.h>
index ec556c92dcb1e9dad4b3d39b511deca39b2a4092..ee035b72aaf9dae1f2f199278341e342ec24f699 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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/buffer.h>
 #include <openssl/asn1.h>
@@ -76,18 +76,7 @@ int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size)
         again = (buf[i - 1] == '\\');
 
         for (j = 0; j < i; j++) {
-#ifndef CHARSET_EBCDIC
-            if (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
-                  ((buf[j] >= 'a') && (buf[j] <= 'f')) ||
-                  ((buf[j] >= 'A') && (buf[j] <= 'F'))))
-#else
-            /*
-             * This #ifdef is not strictly necessary, since the characters
-             * A...F a...f 0...9 are contiguous (yes, even in EBCDIC - but
-             * not the whole alphabet). Nevertheless, isxdigit() is faster.
-             */
-            if (!isxdigit(buf[j]))
-#endif
+            if (!ossl_isxdigit(buf[j]))
             {
                 i = j;
                 break;
index b9258bba8b62fcb613c4f5fba7041506c05003bd..cfb895f2473cd616fae09d75f1bc583e3ee5acd4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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/buffer.h>
 #include <openssl/asn1.h>
@@ -47,7 +47,7 @@ int i2a_ASN1_STRING(BIO *bp, const ASN1_STRING *a, int type)
 
 int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size)
 {
-    int i, j, k, m, n, again, bufsize, spec_char;
+    int i, j, k, m, n, again, bufsize;
     unsigned char *s = NULL, *sp;
     unsigned char *bufp;
     int num = 0, slen = 0, first = 1;
@@ -74,19 +74,7 @@ int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size)
         again = (buf[i - 1] == '\\');
 
         for (j = i - 1; j > 0; j--) {
-#ifndef CHARSET_EBCDIC
-            spec_char = (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
-                  ((buf[j] >= 'a') && (buf[j] <= 'f')) ||
-                  ((buf[j] >= 'A') && (buf[j] <= 'F'))));
-#else
-            /*
-             * This #ifdef is not strictly necessary, since the characters
-             * A...F a...f 0...9 are contiguous (yes, even in EBCDIC - but
-             * not the whole alphabet). Nevertheless, isxdigit() is faster.
-             */
-            spec_char = (!isxdigit(buf[j]));
-#endif
-            if (spec_char) {
+            if (!ossl_isxdigit(buf[j])) {
                 i = j;
                 break;
             }
index d0b2428450c6e6941228e21b34c89b6ac806bff2..6d854927fe9105e7bfbe4e190a3fd32a6c82900d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-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
@@ -17,7 +17,6 @@
 #include <openssl/err.h>
 #include <openssl/buffer.h>
 #include <internal/thread_once.h>
-#include <ctype.h>
 
 CRYPTO_RWLOCK *bio_lookup_lock;
 static CRYPTO_ONCE bio_lookup_init = CRYPTO_ONCE_STATIC_INIT;
index ebb6845dbd7bc7f86deed4e30a6326f2cf631711..eeee52e8c1a1360ad10499553a7c8f890b691b4b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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 <string.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include "internal/numbers.h"
 #include "internal/cryptlib.h"
 #include <openssl/bio.h>
@@ -143,7 +143,7 @@ _dopr(char **sbuffer,
             }
             break;
         case DP_S_MIN:
-            if (isdigit((unsigned char)ch)) {
+            if (ossl_isdigit(ch)) {
                 min = 10 * min + char_to_int(ch);
                 ch = *format++;
             } else if (ch == '*') {
@@ -161,7 +161,7 @@ _dopr(char **sbuffer,
                 state = DP_S_MOD;
             break;
         case DP_S_MAX:
-            if (isdigit((unsigned char)ch)) {
+            if (ossl_isdigit(ch)) {
                 if (max < 0)
                     max = 0;
                 max = 10 * max + char_to_int(ch);
index 9f849978d8bcb4c2e680d0ed77e698a83216d625..bfbaf5c33eeccde2d22cc3cd3e39a58ac62e306c 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include <stdio.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include <limits.h>
 #include "internal/cryptlib.h"
 #include <openssl/buffer.h>
@@ -138,7 +138,7 @@ int BN_hex2bn(BIGNUM **bn, const char *a)
         a++;
     }
 
-    for (i = 0; i <= (INT_MAX/4) && isxdigit((unsigned char)a[i]); i++)
+    for (i = 0; i <= (INT_MAX/4) && ossl_isxdigit(a[i]); i++)
         continue;
 
     if (i == 0 || i > INT_MAX/4)
@@ -210,7 +210,7 @@ int BN_dec2bn(BIGNUM **bn, const char *a)
         a++;
     }
 
-    for (i = 0; i <= (INT_MAX/4) && isdigit((unsigned char)a[i]); i++)
+    for (i = 0; i <= (INT_MAX/4) && ossl_isdigit(a[i]); i++)
         continue;
 
     if (i == 0 || i > INT_MAX/4)
index 916d24f66ed55ed2bf42583c9eb9089f0a1c0c9a..983708a41ba4c00dfd0e60b63b940148ff7e2167 100644 (file)
@@ -2,7 +2,7 @@
 LIBS=../libcrypto
 SOURCE[../libcrypto]=\
         cryptlib.c mem.c mem_dbg.c cversion.c ex_data.c cpt_err.c \
-        ebcdic.c uid.c o_time.c o_str.c o_dir.c o_fopen.c \
+        ebcdic.c uid.c o_time.c o_str.c o_dir.c o_fopen.c ctype.c \
         threads_pthread.c threads_win.c threads_none.c \
         o_init.c o_fips.c mem_sec.c init.c {- $target{cpuid_asm_src} -} \
         {- $target{uplink_aux_src} -}
diff --git a/crypto/ctype.c b/crypto/ctype.c
new file mode 100644 (file)
index 0000000..89ed5bf
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include "internal/ctype.h"
+#include "openssl/ebcdic.h"
+
+/*
+ * Define the character classes for each character in the seven bit ASCII
+ * character set.  This is independent of the host's character set, characters
+ * are converted to ASCII before being used as an index in to this table.
+ * Characters outside of the seven bit ASCII range are detected before indexing.
+ */
+static const unsigned short ctype_char_map[128] = {
+   /* 00 nul */ CTYPE_MASK_cntrl,
+   /* 01 soh */ CTYPE_MASK_cntrl,
+   /* 02 stx */ CTYPE_MASK_cntrl,
+   /* 03 etx */ CTYPE_MASK_cntrl,
+   /* 04 eot */ CTYPE_MASK_cntrl,
+   /* 05 enq */ CTYPE_MASK_cntrl,
+   /* 06 ack */ CTYPE_MASK_cntrl,
+   /* 07 \a  */ CTYPE_MASK_cntrl,
+   /* 08 \b  */ CTYPE_MASK_cntrl,
+   /* 09 \t  */ CTYPE_MASK_blank | CTYPE_MASK_cntrl | CTYPE_MASK_space,
+   /* 0A \n  */ CTYPE_MASK_cntrl | CTYPE_MASK_space,
+   /* 0B \v  */ CTYPE_MASK_cntrl | CTYPE_MASK_space,
+   /* 0C \f  */ CTYPE_MASK_cntrl | CTYPE_MASK_space,
+   /* 0D \r  */ CTYPE_MASK_cntrl | CTYPE_MASK_space,
+   /* 0E so  */ CTYPE_MASK_cntrl,
+   /* 0F si  */ CTYPE_MASK_cntrl,
+   /* 10 dle */ CTYPE_MASK_cntrl,
+   /* 11 dc1 */ CTYPE_MASK_cntrl,
+   /* 12 dc2 */ CTYPE_MASK_cntrl,
+   /* 13 dc3 */ CTYPE_MASK_cntrl,
+   /* 14 dc4 */ CTYPE_MASK_cntrl,
+   /* 15 nak */ CTYPE_MASK_cntrl,
+   /* 16 syn */ CTYPE_MASK_cntrl,
+   /* 17 etb */ CTYPE_MASK_cntrl,
+   /* 18 can */ CTYPE_MASK_cntrl,
+   /* 19 em  */ CTYPE_MASK_cntrl,
+   /* 1A sub */ CTYPE_MASK_cntrl,
+   /* 1B esc */ CTYPE_MASK_cntrl,
+   /* 1C fs  */ CTYPE_MASK_cntrl,
+   /* 1D gs  */ CTYPE_MASK_cntrl,
+   /* 1E rs  */ CTYPE_MASK_cntrl,
+   /* 1F us  */ CTYPE_MASK_cntrl,
+   /* 20     */ CTYPE_MASK_blank | CTYPE_MASK_print | CTYPE_MASK_space
+                | CTYPE_MASK_asn1print,
+   /* 21  !  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 22  "  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 23  #  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 24  $  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 25  %  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 26  &  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 27  '  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_asn1print,
+   /* 28  (  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_asn1print,
+   /* 29  )  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_asn1print,
+   /* 2A  *  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 2B  +  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 2C  ,  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_asn1print,
+   /* 2D  -  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_asn1print,
+   /* 2E  .  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_asn1print,
+   /* 2F  /  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 30  0  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 31  1  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 32  2  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 33  3  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 34  4  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 35  5  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 36  6  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 37  7  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 38  8  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 39  9  */ CTYPE_MASK_digit | CTYPE_MASK_graph | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 3A  :  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_asn1print,
+   /* 3B  ;  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 3C  <  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 3D  =  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 3E  >  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 3F  ?  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct
+                | CTYPE_MASK_asn1print,
+   /* 40  @  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 41  A  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 42  B  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 43  C  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 44  D  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 45  E  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 46  F  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 47  G  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 48  H  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 49  I  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 4A  J  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 4B  K  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 4C  L  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 4D  M  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 4E  N  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 4F  O  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 50  P  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 51  Q  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 52  R  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 53  S  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 54  T  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 55  U  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 56  V  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 57  W  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 58  X  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 59  Y  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 5A  Z  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_upper
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 5B  [  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 5C  \  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 5D  ]  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 5E  ^  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 5F  _  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 60  `  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 61  a  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 62  b  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 63  c  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 64  d  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 65  e  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 66  f  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_xdigit | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 67  g  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 68  h  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 69  i  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 6A  j  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 6B  k  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 6C  l  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 6D  m  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 6E  n  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 6F  o  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 70  p  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 71  q  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 72  r  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 73  s  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 74  t  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 75  u  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 76  v  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 77  w  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 78  x  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 79  y  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 7A  z  */ CTYPE_MASK_graph | CTYPE_MASK_lower | CTYPE_MASK_print
+                | CTYPE_MASK_base64 | CTYPE_MASK_asn1print,
+   /* 7B  {  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 7C  |  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 7D  }  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 7E  ~  */ CTYPE_MASK_graph | CTYPE_MASK_print | CTYPE_MASK_punct,
+   /* 7F del */ CTYPE_MASK_cntrl
+};
+
+#ifdef CHARSET_EBCDIC
+int ossl_toascii(int c)
+{
+    if (c < -128 || c > 256)
+        return c;
+    /*
+     * Adjust negatively signed characters.
+     * This is not required for ASCII because any character that sign extends
+     * is not seven bit and all of the checks are on the seven bit characters.
+     * I.e. any check must fail on sign extension.
+     */
+    if (c < 0)
+        c += 256;
+    return os_toascii[c];
+}
+
+int ossl_fromascii(int c)
+{
+    if (c < -128 || c > 256)
+        return c;
+    if (c < 0)
+        c += 256;
+    return os_toebcdic[c];
+}
+#endif
+
+int ossl_ctype_check(int c, unsigned int mask)
+{
+    const int max = sizeof(ctype_char_map) / sizeof(*ctype_char_map);
+
+    c = ossl_toascii(c);
+    return c >= 0 && c < max && (ctype_char_map[c] & mask) != 0;
+}
+
+#if defined(CHARSET_EBCDIC) && !defined(CHARSET_EBCDIC_TEST)
+static const int case_change = 0x40;
+#else
+static const int case_change = 0x20;
+#endif
+
+int ossl_tolower(int c)
+{
+    return ossl_isupper(c) ? c ^ case_change : c;
+}
+
+int ossl_toupper(int c)
+{
+    return ossl_islower(c) ? c ^ case_change : c;
+}
index d0d61b28bed8fd714919501e811c69577f522b9a..8df2c06e1f529deeb2d8535df0c5dfdf40623cc5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2012-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,6 @@
  */
 
 #include <stdio.h>
-#include <ctype.h>
 #include <openssl/crypto.h>
 #include "internal/cryptlib.h"
 #include <openssl/conf.h>
diff --git a/crypto/include/internal/ctype.h b/crypto/include/internal/ctype.h
new file mode 100644 (file)
index 0000000..a35b12b
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * This version of ctype.h provides a standardised and platform
+ * independent implementation that supports seven bit ASCII characters.
+ * The specific intent is to not pass extended ASCII characters (> 127)
+ * even if the host operating system would.
+ *
+ * There is EBCDIC support included for machines which use this.  However,
+ * there are a number of concerns about how well EBCDIC is supported
+ * throughout the rest of the source code.  Refer to issue #4154 for
+ * details.
+ */
+#ifndef INTERNAL_CTYPE_H
+# define INTERNAL_CTYPE_H
+
+# define CTYPE_MASK_lower       0x1
+# define CTYPE_MASK_upper       0x2
+# define CTYPE_MASK_digit       0x4
+# define CTYPE_MASK_space       0x8
+# define CTYPE_MASK_xdigit      0x10
+# define CTYPE_MASK_blank       0x20
+# define CTYPE_MASK_cntrl       0x40
+# define CTYPE_MASK_graph       0x80
+# define CTYPE_MASK_print       0x100
+# define CTYPE_MASK_punct       0x200
+# define CTYPE_MASK_base64      0x400
+# define CTYPE_MASK_asn1print   0x800
+
+# define CTYPE_MASK_alpha   (CTYPE_MASK_lower | CTYPE_MASK_upper)
+# define CTYPE_MASK_alnum   (CTYPE_MASK_alpha | CTYPE_MASK_digit)
+
+/*
+ * The ascii mask assumes that any other classification implies that
+ * the character is ASCII and that there are no ASCII characters
+ * that aren't in any of the classifications.
+ *
+ * This assumption holds at the moment, but it might not in the future.
+ */
+# define CTYPE_MASK_ascii   (~0)
+
+# ifdef CHARSET_EBCDIC
+int ossl_toascii(int c);
+int ossl_fromascii(int c);
+# else
+#  define ossl_toascii(c)       (c)
+#  define ossl_fromascii(c)     (c)
+# endif
+int ossl_ctype_check(int c, unsigned int mask);
+int ossl_tolower(int c);
+int ossl_toupper(int c);
+
+# define ossl_isalnum(c)        (ossl_ctype_check((c), CTYPE_MASK_alnum))
+# define ossl_isalpha(c)        (ossl_ctype_check((c), CTYPE_MASK_alpha))
+# ifdef CHARSET_EBCDIC
+# define ossl_isascii(c)        (ossl_ctype_check((c), CTYPE_MASK_ascii))
+# else
+# define ossl_isascii(c)        (((c) & ~127) == 0)
+# endif
+# define ossl_isblank(c)        (ossl_ctype_check((c), CTYPE_MASK_blank))
+# define ossl_iscntrl(c)        (ossl_ctype_check((c), CTYPE_MASK_cntrl))
+# define ossl_isdigit(c)        (ossl_ctype_check((c), CTYPE_MASK_digit))
+# define ossl_isgraph(c)        (ossl_ctype_check((c), CTYPE_MASK_graph))
+# define ossl_islower(c)        (ossl_ctype_check((c), CTYPE_MASK_lower))
+# define ossl_isprint(c)        (ossl_ctype_check((c), CTYPE_MASK_print))
+# define ossl_ispunct(c)        (ossl_ctype_check((c), CTYPE_MASK_punct))
+# define ossl_isspace(c)        (ossl_ctype_check((c), CTYPE_MASK_space))
+# define ossl_isupper(c)        (ossl_ctype_check((c), CTYPE_MASK_upper))
+# define ossl_isxdigit(c)       (ossl_ctype_check((c), CTYPE_MASK_xdigit))
+# define ossl_isbase64(c)       (ossl_ctype_check((c), CTYPE_MASK_base64))
+# define ossl_isasn1print(c)    (ossl_ctype_check((c), CTYPE_MASK_asn1print))
+
+#endif
index 528655aa8ce8a8529819ee3080387104cf852f92..c762b7009bbf52b3f1e0a4284c2015016f3a221f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2003-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
@@ -7,7 +7,6 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include <ctype.h>
 #include <limits.h>
 #include <e_os.h>
 #include <openssl/crypto.h>
index 4de346b5cbf6a5ad6ea5483c3d9287751e00655a..3f65d37bc689c0a29a35a5b0bc32878a3630a401 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include <stdio.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include <limits.h>
 #include "internal/cryptlib.h"
 #include <openssl/lhash.h>
@@ -644,24 +644,24 @@ int OBJ_create_objects(BIO *in)
         if (i <= 0)
             return num;
         buf[i - 1] = '\0';
-        if (!isalnum((unsigned char)buf[0]))
+        if (!ossl_isalnum(buf[0]))
             return num;
         o = s = buf;
-        while (isdigit((unsigned char)*s) || (*s == '.'))
+        while (ossl_isdigit(*s) || *s == '.')
             s++;
         if (*s != '\0') {
             *(s++) = '\0';
-            while (isspace((unsigned char)*s))
+            while (ossl_isspace(*s))
                 s++;
             if (*s == '\0')
                 s = NULL;
             else {
                 l = s;
-                while ((*l != '\0') && !isspace((unsigned char)*l))
+                while (*l != '\0' && !ossl_isspace(*l))
                     l++;
                 if (*l != '\0') {
                     *(l++) = '\0';
-                    while (isspace((unsigned char)*l))
+                    while (ossl_isspace(*l))
                         l++;
                     if (*l == '\0')
                         l = NULL;
index d8796ca6bf54cf13401b2811032e6ab18b5dadaa..ef84a2d4c9e42e70cd08605bb437cda3c56b694e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2001-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 <stdlib.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include <string.h>
 #include "e_os.h"
 #include <openssl/asn1.h>
@@ -209,7 +209,7 @@ static int parse_http_line1(char *line)
     char *p, *q, *r;
     /* Skip to first white space (passed protocol info) */
 
-    for (p = line; *p && !isspace((unsigned char)*p); p++)
+    for (p = line; *p && !ossl_isspace(*p); p++)
         continue;
     if (!*p) {
         OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
@@ -217,7 +217,7 @@ static int parse_http_line1(char *line)
     }
 
     /* Skip past white space to start of response code */
-    while (*p && isspace((unsigned char)*p))
+    while (*p && ossl_isspace(*p))
         p++;
 
     if (!*p) {
@@ -226,7 +226,7 @@ static int parse_http_line1(char *line)
     }
 
     /* Find end of response code: first whitespace after start of code */
-    for (q = p; *q && !isspace((unsigned char)*q); q++)
+    for (q = p; *q && !ossl_isspace(*q); q++)
         continue;
 
     if (!*q) {
@@ -244,7 +244,7 @@ static int parse_http_line1(char *line)
         return 0;
 
     /* Skip over any leading white space in message */
-    while (*q && isspace((unsigned char)*q))
+    while (*q && ossl_isspace(*q))
         q++;
 
     if (*q) {
@@ -253,7 +253,7 @@ static int parse_http_line1(char *line)
          */
 
         /* We know q has a non white space character so this is OK */
-        for (r = q + strlen(q) - 1; isspace((unsigned char)*r); r--)
+        for (r = q + strlen(q) - 1; ossl_isspace(*r); r--)
             *r = 0;
     }
     if (retcode != 200) {
index 309545b04d5f51188859f42eaeaee0894c340826..97b8a0d7c0ab8baa9107f873c18ff046c74102f6 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include <stdio.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include <string.h>
 #include "internal/cryptlib.h"
 #include <openssl/buffer.h>
@@ -683,9 +683,6 @@ int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
 #endif
 
 /* Some helpers for PEM_read_bio_ex(). */
-
-#define isb64(c) (isalnum(c) || (c) == '+' || (c) == '/' || (c) == '=')
-
 static int sanitize_line(char *linebuf, int len, unsigned int flags)
 {
     int i;
@@ -698,7 +695,8 @@ static int sanitize_line(char *linebuf, int len, unsigned int flags)
         len++;
     } else if (flags & PEM_FLAG_ONLY_B64) {
         for (i = 0; i < len; ++i) {
-            if (!isb64(linebuf[i]) || linebuf[i] == '\n' || linebuf[i] == '\r')
+            if (!ossl_isbase64(linebuf[i]) || linebuf[i] == '\n'
+                || linebuf[i] == '\r')
                 break;
         }
         len = i;
@@ -708,7 +706,7 @@ static int sanitize_line(char *linebuf, int len, unsigned int flags)
         for (i = 0; i < len; ++i) {
             if (linebuf[i] == '\n' || linebuf[i] == '\r')
                 break;
-            if (iscntrl(linebuf[i]))
+            if (ossl_iscntrl(linebuf[i]))
                 linebuf[i] = ' ';
         }
         len = i;
index 97474cf5194a7464cc9c11d9b54466420b57c2c5..19e6868148b8dfa195e082aa0a284712a9d45ad2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-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,6 @@
  */
 
 #include <stdio.h>
-#include <ctype.h>
 #include "internal/cryptlib.h"
 #include <openssl/x509.h>
 #include <openssl/asn1.h>
index 99c9350cf80399b94058bc95c6855b39c364c79d..f6cb928ae3c306015ab76f1c0756732a9cfdabda 100644 (file)
@@ -23,6 +23,7 @@
 #include <openssl/ui.h>
 #include <openssl/x509.h>        /* For the PKCS8 stuff o.O */
 #include "internal/asn1_int.h"
+#include "internal/ctype.h"
 #include "internal/o_dir.h"
 #include "internal/cryptlib.h"
 #include "internal/store_int.h"
@@ -783,7 +784,7 @@ static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader,
 #ifdef _WIN32
         /* Windows file: URIs with a drive letter start with a / */
         if (p[0] == '/' && p[2] == ':' && p[3] == '/') {
-            char c = tolower(p[1]);
+            char c = ossl_tolower(p[1]);
 
             if (c >= 'a' && c <= 'z') {
                 p++;
index 6af7144f5c9b39109d37a0a90b155bb5ac1ea761..85c38b84dd127e55e081ee6b880c45e530d530f4 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include <string.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include <assert.h>
 
 #include <openssl/err.h>
@@ -140,10 +140,10 @@ int ossl_store_register_loader_int(OSSL_STORE_LOADER *loader)
      *
      * scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
      */
-    if (isalpha(*scheme))
+    if (ossl_isalpha(*scheme))
         while (*scheme != '\0'
-               && (isalpha(*scheme)
-                   || isdigit(*scheme)
+               && (ossl_isalpha(*scheme)
+                   || ossl_isdigit(*scheme)
                    || strchr("+-.", *scheme) != NULL))
             scheme++;
     if (*scheme != '\0') {
index 01056356c5834137ca54a6909b97b80937a560d9..a5903fd97b1c04f0e2eaf18b16374d1d5c3b1ac2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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,6 @@
  */
 
 #include <stdio.h>
-#include <ctype.h>
 #include "internal/cryptlib.h"
 #include <openssl/asn1.h>
 #include <openssl/objects.h>
index af96418e857e645199e90de256b6515710b958b1..58f88ba4fa73df6ac351ab065ab79ac22cc9f750 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -7,12 +7,12 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include <ctype.h>
 #include <stdio.h>
 #include <time.h>
 #include <errno.h>
 #include <limits.h>
 
+#include "internal/ctype.h"
 #include "internal/cryptlib.h"
 #include <openssl/crypto.h>
 #include <openssl/lhash.h>
@@ -1790,7 +1790,7 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
      * Digit and date ranges will be verified in the conversion methods.
      */
     for (i = 0; i < ctm->length - 1; i++) {
-        if (!isdigit(ctm->data[i]))
+        if (!ossl_isdigit(ctm->data[i]))
             return 0;
     }
     if (ctm->data[ctm->length - 1] != 'Z')
index 97d735f8f2c036db41d85df60d19d084f311e9fb..665a52082f8e5f7956789ec5759db93f4d21ae35 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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/asn1t.h>
 #include <openssl/x509.h>
@@ -398,11 +398,12 @@ static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in)
     /*
      * Convert string in place to canonical form. Ultimately we may need to
      * handle a wider range of characters but for now ignore anything with
-     * MSB set and rely on the isspace() and tolower() functions.
+     * MSB set and rely on the ossl_isspace() to fail on bad characters without
+     * needing isascii or range checks as well.
      */
 
     /* Ignore leading spaces */
-    while ((len > 0) && !(*from & 0x80) && isspace(*from)) {
+    while (len > 0 && ossl_isspace(*from)) {
         from++;
         len--;
     }
@@ -410,7 +411,7 @@ static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in)
     to = from + len;
 
     /* Ignore trailing spaces */
-    while ((len > 0) && !(to[-1] & 0x80) && isspace(to[-1])) {
+    while (len > 0 && ossl_isspace(to[-1])) {
         to--;
         len--;
     }
@@ -419,13 +420,13 @@ static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in)
 
     i = 0;
     while (i < len) {
-        /* If MSB set just copy across */
-        if (*from & 0x80) {
+        /* If not ASCII set just copy across */
+        if (!ossl_isascii(*from)) {
             *to++ = *from++;
             i++;
         }
         /* Collapse multiple spaces */
-        else if (isspace(*from)) {
+        else if (ossl_isspace(*from)) {
             /* Copy one space across */
             *to++ = ' ';
             /*
@@ -437,9 +438,9 @@ static int asn1_string_canon(ASN1_STRING *out, const ASN1_STRING *in)
                 from++;
                 i++;
             }
-            while (!(*from & 0x80) && isspace(*from));
+            while (ossl_isspace(*from));
         } else {
-            *to++ = tolower(*from);
+            *to++ = ossl_tolower(*from);
             from++;
             i++;
         }
@@ -505,19 +506,10 @@ int X509_NAME_print(BIO *bp, const X509_NAME *name, int obase)
 
     c = s;
     for (;;) {
-#ifndef CHARSET_EBCDIC
         if (((*s == '/') &&
-             ((s[1] >= 'A') && (s[1] <= 'Z') && ((s[2] == '=') ||
-                                                 ((s[2] >= 'A')
-                                                  && (s[2] <= 'Z')
-                                                  && (s[3] == '='))
+             (ossl_isupper(s[1]) && ((s[2] == '=') ||
+                                (ossl_isupper(s[2]) && (s[3] == '='))
               ))) || (*s == '\0'))
-#else
-        if (((*s == '/') &&
-             (isupper(s[1]) && ((s[2] == '=') ||
-                                (isupper(s[2]) && (s[3] == '='))
-              ))) || (*s == '\0'))
-#endif
         {
             i = s - c;
             if (BIO_write(bp, c, i) != i)
index f625ff542eea98807162327a40c621e46c0d1012..711ff02fb06b997b45d903f64683c6b81022d74b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-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
@@ -10,7 +10,7 @@
 /* extension creation utilities */
 
 #include <stdio.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include "internal/cryptlib.h"
 #include <openssl/conf.h>
 #include <openssl/x509.h>
@@ -192,7 +192,7 @@ static int v3_check_critical(const char **value)
     if ((strlen(p) < 9) || strncmp(p, "critical,", 9))
         return 0;
     p += 9;
-    while (isspace((unsigned char)*p))
+    while (ossl_isspace(*p))
         p++;
     *value = p;
     return 1;
@@ -212,7 +212,7 @@ static int v3_check_generic(const char **value)
     } else
         return 0;
 
-    while (isspace((unsigned char)*p))
+    while (ossl_isspace(*p))
         p++;
     *value = p;
     return gen_type;
index ac5217053a5aa14ea7425cb4b301aa00efa0d2ea..a10722cf16a86e89e9aa4ac203cb0021f7e26ac0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-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
@@ -10,7 +10,7 @@
 /* X509 v3 extension utilities */
 
 #include <stdio.h>
-#include <ctype.h>
+#include "internal/ctype.h"
 #include "internal/cryptlib.h"
 #include <openssl/conf.h>
 #include <openssl/x509v3.h>
@@ -334,12 +334,12 @@ static char *strip_spaces(char *name)
     char *p, *q;
     /* Skip over leading spaces */
     p = name;
-    while (*p && isspace((unsigned char)*p))
+    while (*p && ossl_isspace(*p))
         p++;
     if (!*p)
         return NULL;
     q = p + strlen(p) - 1;
-    while ((q != p) && isspace((unsigned char)*q))
+    while ((q != p) && ossl_isspace(*q))
         q--;
     if (p != q)
         q[1] = 0;
index 6abd63523124e3ab36740e2728019e1ca7bbd513..f1f26afef279ab8da7e319014a2cec22d91381dd 100644 (file)
@@ -385,7 +385,7 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN
   # names with the DLL import libraries.
   IF[{- $disabled{shared} || $target{build_scheme}->[1] ne 'windows' -}]
     PROGRAMS_NO_INST=asn1_internal_test modes_internal_test x509_internal_test \
-                     tls13encryptiontest wpackettest
+                     tls13encryptiontest wpackettest ctype_internal_test
     IF[{- !$disabled{poly1305} -}]
       PROGRAMS_NO_INST=poly1305_internal_test
     ENDIF
@@ -424,6 +424,10 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN
     INCLUDE[wpackettest]=../include
     DEPEND[wpackettest]=../libcrypto ../libssl.a libtestutil.a
 
+    SOURCE[ctype_internal_test]=ctype_internal_test.c
+    INCLUDE[ctype_internal_test]=.. ../crypto/include ../include
+    DEPEND[ctype_internal_test]=../libcrypto.a libtestutil.a
+
     SOURCE[siphash_internal_test]=siphash_internal_test.c
     INCLUDE[siphash_internal_test]=.. ../include ../crypto/include
     DEPEND[siphash_internal_test]=../libcrypto.a libtestutil.a
diff --git a/test/ctype_internal_test.c b/test/ctype_internal_test.c
new file mode 100644 (file)
index 0000000..0a30c3d
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "testutil.h"
+#include "internal/ctype.h"
+#include "../e_os.h"
+#include <ctype.h>
+#include <stdio.h>
+
+static int test_ctype_chars(int n)
+{
+    return TEST_int_eq(isalnum(n) != 0, ossl_isalnum(n) != 0)
+           && TEST_int_eq(isalpha(n) != 0, ossl_isalpha(n) != 0)
+           && TEST_int_eq(isascii(n) != 0, ossl_isascii(n) != 0)
+           && TEST_int_eq(isblank(n) != 0, ossl_isblank(n) != 0)
+           && TEST_int_eq(iscntrl(n) != 0, ossl_iscntrl(n) != 0)
+           && TEST_int_eq(isdigit(n) != 0, ossl_isdigit(n) != 0)
+           && TEST_int_eq(isgraph(n) != 0, ossl_isgraph(n) != 0)
+           && TEST_int_eq(islower(n) != 0, ossl_islower(n) != 0)
+           && TEST_int_eq(isprint(n) != 0, ossl_isprint(n) != 0)
+           && TEST_int_eq(ispunct(n) != 0, ossl_ispunct(n) != 0)
+           && TEST_int_eq(isspace(n) != 0, ossl_isspace(n) != 0)
+           && TEST_int_eq(isupper(n) != 0, ossl_isupper(n) != 0)
+           && TEST_int_eq(isxdigit(n) != 0, ossl_isxdigit(n) != 0);
+}
+
+static int test_ctype_negative(int n)
+{
+    return test_ctype_chars(-n);
+}
+
+static struct {
+    int u;
+    int l;
+} case_change[] = {
+    { 'A', 'a' },
+    { 'X', 'x' },
+    { 'Z', 'z' },
+    { '0', '0' },
+    { '%', '%' },
+    { '~', '~' },
+    {   0,   0 },
+    { EOF, EOF },
+    { 333, 333 },
+    { -333, -333 },
+    { -128, -128 }
+};
+
+static int test_ctype_toupper(int n)
+{
+    return TEST_int_eq(ossl_toupper(case_change[n].l), case_change[n].u)
+           && TEST_int_eq(ossl_toupper(case_change[n].u), case_change[n].u);
+}
+
+static int test_ctype_tolower(int n)
+{
+    return TEST_int_eq(ossl_tolower(case_change[n].u), case_change[n].l)
+           && TEST_int_eq(ossl_tolower(case_change[n].l), case_change[n].l);
+}
+
+int setup_tests(void)
+{
+    ADD_ALL_TESTS(test_ctype_chars, 256);
+    ADD_ALL_TESTS(test_ctype_negative, 128);
+    ADD_ALL_TESTS(test_ctype_toupper, OSSL_NELEM(case_change));
+    ADD_ALL_TESTS(test_ctype_tolower, OSSL_NELEM(case_change));
+    return 1;
+}
diff --git a/test/recipes/02-test_internal_ctype.t b/test/recipes/02-test_internal_ctype.t
new file mode 100644 (file)
index 0000000..5bf81bd
--- /dev/null
@@ -0,0 +1,20 @@
+#! /usr/bin/env perl
+# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright (c) 2017, Oracle and/or its affiliates.  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
+
+use strict;
+use OpenSSL::Test;              # get 'plan'
+use OpenSSL::Test::Simple;
+use OpenSSL::Test::Utils;
+
+setup("test_internal_ctype");
+
+plan skip_all => "This test is unsupported in a shared library build on Windows"
+    if $^O eq 'MSWin32' && !disabled("shared");
+
+simple_test("test_internal_ctype", "ctype_internal_test");