aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPauli <paul.dale@oracle.com>2017-08-21 07:19:17 +1000
committerPauli <paul.dale@oracle.com>2017-08-22 09:45:25 +1000
commita1df06b36347a31c17d09e6ca3e1464bdf7eb4d5 (patch)
treebeb260df46896a5c8668dd7f64c5dcefe677b1e6
parent00dfbaad88a69ed8294d6039bf5f7d722f72bf39 (diff)
downloadopenssl-a1df06b36347a31c17d09e6ca3e1464bdf7eb4d5.tar.gz
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: Andy Polyakov <appro@openssl.org> (Merged from https://github.com/openssl/openssl/pull/4102)
-rw-r--r--crypto/asn1/a_gentm.c1
-rw-r--r--crypto/asn1/a_mbstr.c68
-rw-r--r--crypto/asn1/a_object.c6
-rw-r--r--crypto/asn1/a_print.c22
-rw-r--r--crypto/asn1/a_strnid.c1
-rw-r--r--crypto/asn1/a_time.c14
-rw-r--r--crypto/asn1/a_utctm.c1
-rw-r--r--crypto/asn1/asn_mime.c40
-rw-r--r--crypto/asn1/asn_moid.c10
-rw-r--r--crypto/asn1/asn_mstbl.c3
-rw-r--r--crypto/asn1/f_int.c17
-rw-r--r--crypto/asn1/f_string.c20
-rw-r--r--crypto/bio/b_addr.c3
-rw-r--r--crypto/bio/b_print.c8
-rw-r--r--crypto/bn/bn_print.c6
-rw-r--r--crypto/build.info2
-rw-r--r--crypto/ctype.c273
-rw-r--r--crypto/evp/evp_cnf.c3
-rw-r--r--crypto/include/internal/ctype.h80
-rw-r--r--crypto/o_str.c3
-rw-r--r--crypto/objects/obj_dat.c12
-rw-r--r--crypto/ocsp/ocsp_ht.c14
-rw-r--r--crypto/pem/pem_lib.c10
-rw-r--r--crypto/pkcs7/pk7_mime.c3
-rw-r--r--crypto/store/loader_file.c3
-rw-r--r--crypto/store/store_register.c8
-rw-r--r--crypto/x509/x509_cmp.c3
-rw-r--r--crypto/x509/x509_vfy.c6
-rw-r--r--crypto/x509/x_name.c34
-rw-r--r--crypto/x509v3/v3_conf.c8
-rw-r--r--crypto/x509v3/v3_utl.c8
-rw-r--r--test/build.info6
-rw-r--r--test/ctype_internal_test.c74
-rw-r--r--test/recipes/02-test_internal_ctype.t20
34 files changed, 559 insertions, 231 deletions
diff --git a/crypto/asn1/a_gentm.c b/crypto/asn1/a_gentm.c
index 4e2e815d27..d3878d6e57 100644
--- a/crypto/asn1/a_gentm.c
+++ b/crypto/asn1/a_gentm.c
@@ -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"
diff --git a/crypto/asn1/a_mbstr.c b/crypto/asn1/a_mbstr.c
index e644fe0542..949fe6c161 100644
--- a/crypto/asn1/a_mbstr.c
+++ b/crypto/asn1/a_mbstr.c
@@ -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;
-}
diff --git a/crypto/asn1/a_object.c b/crypto/asn1/a_object.c
index 5ae56a24ea..566d8b352c 100644
--- a/crypto/asn1/a_object.c
+++ b/crypto/asn1/a_object.c
@@ -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;
}
diff --git a/crypto/asn1/a_print.c b/crypto/asn1/a_print.c
index 1aafe7c839..ed72b51926 100644
--- a/crypto/asn1/a_print.c
+++ b/crypto/asn1/a_print.c
@@ -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);
diff --git a/crypto/asn1/a_strnid.c b/crypto/asn1/a_strnid.c
index 04c77eb452..a7d6b0e3df 100644
--- a/crypto/asn1/a_strnid.c
+++ b/crypto/asn1/a_strnid.c
@@ -8,7 +8,6 @@
*/
#include <stdio.h>
-#include <ctype.h>
#include "internal/cryptlib.h"
#include <openssl/asn1.h>
#include <openssl/objects.h>
diff --git a/crypto/asn1/a_time.c b/crypto/asn1/a_time.c
index 507292b76e..cb19e8024a 100644
--- a/crypto/asn1/a_time.c
+++ b/crypto/asn1/a_time.c
@@ -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;
}
diff --git a/crypto/asn1/a_utctm.c b/crypto/asn1/a_utctm.c
index b88aa4218e..b224991aa3 100644
--- a/crypto/asn1/a_utctm.c
+++ b/crypto/asn1/a_utctm.c
@@ -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"
diff --git a/crypto/asn1/asn_mime.c b/crypto/asn1/asn_mime.c
index d7ec801b1e..01638da127 100644
--- a/crypto/asn1/asn_mime.c
+++ b/crypto/asn1/asn_mime.c
@@ -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);
diff --git a/crypto/asn1/asn_moid.c b/crypto/asn1/asn_moid.c
index 8176b76008..ed8517c372 100644
--- a/crypto/asn1/asn_moid.c
+++ b/crypto/asn1/asn_moid.c
@@ -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--;
diff --git a/crypto/asn1/asn_mstbl.c b/crypto/asn1/asn_mstbl.c
index 8260939002..ddcbcd07fe 100644
--- a/crypto/asn1/asn_mstbl.c
+++ b/crypto/asn1/asn_mstbl.c
@@ -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/asn1/f_int.c b/crypto/asn1/f_int.c
index ec556c92dc..ee035b72aa 100644
--- a/crypto/asn1/f_int.c
+++ b/crypto/asn1/f_int.c
@@ -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;
diff --git a/crypto/asn1/f_string.c b/crypto/asn1/f_string.c
index b9258bba8b..cfb895f247 100644
--- a/crypto/asn1/f_string.c
+++ b/crypto/asn1/f_string.c
@@ -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;
}
diff --git a/crypto/bio/b_addr.c b/crypto/bio/b_addr.c
index d0b2428450..6d854927fe 100644
--- a/crypto/bio/b_addr.c
+++ b/crypto/bio/b_addr.c
@@ -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;
diff --git a/crypto/bio/b_print.c b/crypto/bio/b_print.c
index ebb6845dbd..eeee52e8c1 100644
--- a/crypto/bio/b_print.c
+++ b/crypto/bio/b_print.c
@@ -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);
diff --git a/crypto/bn/bn_print.c b/crypto/bn/bn_print.c
index 9f849978d8..bfbaf5c33e 100644
--- a/crypto/bn/bn_print.c
+++ b/crypto/bn/bn_print.c
@@ -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)
diff --git a/crypto/build.info b/crypto/build.info
index 916d24f66e..983708a41b 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -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
index 0000000000..89ed5bf486
--- /dev/null
+++ b/crypto/ctype.c
@@ -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;
+}
diff --git a/crypto/evp/evp_cnf.c b/crypto/evp/evp_cnf.c
index d0d61b28be..8df2c06e1f 100644
--- a/crypto/evp/evp_cnf.c
+++ b/crypto/evp/evp_cnf.c
@@ -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
index 0000000000..a35b12bfbf
--- /dev/null
+++ b/crypto/include/internal/ctype.h
@@ -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
diff --git a/crypto/o_str.c b/crypto/o_str.c
index 528655aa8c..c762b7009b 100644
--- a/crypto/o_str.c
+++ b/crypto/o_str.c
@@ -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>
diff --git a/crypto/objects/obj_dat.c b/crypto/objects/obj_dat.c
index 4de346b5cb..3f65d37bc6 100644
--- a/crypto/objects/obj_dat.c
+++ b/crypto/objects/obj_dat.c
@@ -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;
diff --git a/crypto/ocsp/ocsp_ht.c b/crypto/ocsp/ocsp_ht.c
index d8796ca6bf..ef84a2d4c9 100644
--- a/crypto/ocsp/ocsp_ht.c
+++ b/crypto/ocsp/ocsp_ht.c
@@ -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) {
diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c
index 309545b04d..97b8a0d7c0 100644
--- a/crypto/pem/pem_lib.c
+++ b/crypto/pem/pem_lib.c
@@ -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;
diff --git a/crypto/pkcs7/pk7_mime.c b/crypto/pkcs7/pk7_mime.c
index 97474cf519..19e6868148 100644
--- a/crypto/pkcs7/pk7_mime.c
+++ b/crypto/pkcs7/pk7_mime.c
@@ -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>
diff --git a/crypto/store/loader_file.c b/crypto/store/loader_file.c
index 99c9350cf8..f6cb928ae3 100644
--- a/crypto/store/loader_file.c
+++ b/crypto/store/loader_file.c
@@ -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++;
diff --git a/crypto/store/store_register.c b/crypto/store/store_register.c
index 6af7144f5c..85c38b84dd 100644
--- a/crypto/store/store_register.c
+++ b/crypto/store/store_register.c
@@ -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') {
diff --git a/crypto/x509/x509_cmp.c b/crypto/x509/x509_cmp.c
index 01056356c5..a5903fd97b 100644
--- a/crypto/x509/x509_cmp.c
+++ b/crypto/x509/x509_cmp.c
@@ -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>
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index af96418e85..58f88ba4fa 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -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')
diff --git a/crypto/x509/x_name.c b/crypto/x509/x_name.c
index 97d735f8f2..665a52082f 100644
--- a/crypto/x509/x_name.c
+++ b/crypto/x509/x_name.c
@@ -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)
diff --git a/crypto/x509v3/v3_conf.c b/crypto/x509v3/v3_conf.c
index f625ff542e..711ff02fb0 100644
--- a/crypto/x509v3/v3_conf.c
+++ b/crypto/x509v3/v3_conf.c
@@ -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;
diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c
index ac5217053a..a10722cf16 100644
--- a/crypto/x509v3/v3_utl.c
+++ b/crypto/x509v3/v3_utl.c
@@ -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;
diff --git a/test/build.info b/test/build.info
index 6abd635231..f1f26afef2 100644
--- a/test/build.info
+++ b/test/build.info
@@ -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
index 0000000000..0a30c3dd84
--- /dev/null
+++ b/test/ctype_internal_test.c
@@ -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
index 0000000000..5bf81bdff1
--- /dev/null
+++ b/test/recipes/02-test_internal_ctype.t
@@ -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");