openssl/crypto/o_str.c
Pauli a1df06b363 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)
2017-08-22 09:45:25 +10:00

250 lines
5.8 KiB
C

/*
* 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
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <limits.h>
#include <e_os.h>
#include <openssl/crypto.h>
#include "internal/cryptlib.h"
#include "internal/o_str.h"
int OPENSSL_memcmp(const void *v1, const void *v2, size_t n)
{
const unsigned char *c1 = v1, *c2 = v2;
int ret = 0;
while (n && (ret = *c1 - *c2) == 0)
n--, c1++, c2++;
return ret;
}
char *CRYPTO_strdup(const char *str, const char* file, int line)
{
char *ret;
size_t size;
if (str == NULL)
return NULL;
size = strlen(str) + 1;
ret = CRYPTO_malloc(size, file, line);
if (ret != NULL)
memcpy(ret, str, size);
return ret;
}
char *CRYPTO_strndup(const char *str, size_t s, const char* file, int line)
{
size_t maxlen;
char *ret;
if (str == NULL)
return NULL;
maxlen = OPENSSL_strnlen(str, s);
ret = CRYPTO_malloc(maxlen + 1, file, line);
if (ret) {
memcpy(ret, str, maxlen);
ret[maxlen] = '\0';
}
return ret;
}
void *CRYPTO_memdup(const void *data, size_t siz, const char* file, int line)
{
void *ret;
if (data == NULL || siz >= INT_MAX)
return NULL;
ret = CRYPTO_malloc(siz, file, line);
if (ret == NULL) {
CRYPTOerr(CRYPTO_F_CRYPTO_MEMDUP, ERR_R_MALLOC_FAILURE);
return NULL;
}
return memcpy(ret, data, siz);
}
size_t OPENSSL_strnlen(const char *str, size_t maxlen)
{
const char *p;
for (p = str; maxlen-- != 0 && *p != '\0'; ++p) ;
return p - str;
}
size_t OPENSSL_strlcpy(char *dst, const char *src, size_t size)
{
size_t l = 0;
for (; size > 1 && *src; size--) {
*dst++ = *src++;
l++;
}
if (size)
*dst = '\0';
return l + strlen(src);
}
size_t OPENSSL_strlcat(char *dst, const char *src, size_t size)
{
size_t l = 0;
for (; size > 0 && *dst; size--, dst++)
l++;
return l + OPENSSL_strlcpy(dst, src, size);
}
int OPENSSL_hexchar2int(unsigned char c)
{
#ifdef CHARSET_EBCDIC
c = os_toebcdic[c];
#endif
switch (c) {
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case 'a': case 'A':
return 0x0A;
case 'b': case 'B':
return 0x0B;
case 'c': case 'C':
return 0x0C;
case 'd': case 'D':
return 0x0D;
case 'e': case 'E':
return 0x0E;
case 'f': case 'F':
return 0x0F;
}
return -1;
}
/*
* Give a string of hex digits convert to a buffer
*/
unsigned char *OPENSSL_hexstr2buf(const char *str, long *len)
{
unsigned char *hexbuf, *q;
unsigned char ch, cl;
int chi, cli;
const unsigned char *p;
size_t s;
s = strlen(str);
if ((hexbuf = OPENSSL_malloc(s >> 1)) == NULL) {
CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, ERR_R_MALLOC_FAILURE);
return NULL;
}
for (p = (const unsigned char *)str, q = hexbuf; *p; ) {
ch = *p++;
if (ch == ':')
continue;
cl = *p++;
if (!cl) {
CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF,
CRYPTO_R_ODD_NUMBER_OF_DIGITS);
OPENSSL_free(hexbuf);
return NULL;
}
cli = OPENSSL_hexchar2int(cl);
chi = OPENSSL_hexchar2int(ch);
if (cli < 0 || chi < 0) {
OPENSSL_free(hexbuf);
CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, CRYPTO_R_ILLEGAL_HEX_DIGIT);
return NULL;
}
*q++ = (unsigned char)((chi << 4) | cli);
}
if (len)
*len = q - hexbuf;
return hexbuf;
}
/*
* Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its
* hex representation @@@ (Contents of buffer are always kept in ASCII, also
* on EBCDIC machines)
*/
char *OPENSSL_buf2hexstr(const unsigned char *buffer, long len)
{
static const char hexdig[] = "0123456789ABCDEF";
char *tmp, *q;
const unsigned char *p;
int i;
if (len == 0)
{
return OPENSSL_zalloc(1);
}
if ((tmp = OPENSSL_malloc(len * 3)) == NULL) {
CRYPTOerr(CRYPTO_F_OPENSSL_BUF2HEXSTR, ERR_R_MALLOC_FAILURE);
return NULL;
}
q = tmp;
for (i = 0, p = buffer; i < len; i++, p++) {
*q++ = hexdig[(*p >> 4) & 0xf];
*q++ = hexdig[*p & 0xf];
*q++ = ':';
}
q[-1] = 0;
#ifdef CHARSET_EBCDIC
ebcdic2ascii(tmp, tmp, q - tmp - 1);
#endif
return tmp;
}
int openssl_strerror_r(int errnum, char *buf, size_t buflen)
{
#if defined(_MSC_VER) && _MSC_VER>=1400
return !strerror_s(buf, buflen, errnum);
#elif defined(_GNU_SOURCE)
return strerror_r(errnum, buf, buflen) != NULL;
#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \
(defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
/*
* We can use "real" strerror_r. The OpenSSL version differs in that it
* gives 1 on success and 0 on failure for consistency with other OpenSSL
* functions. Real strerror_r does it the other way around
*/
return !strerror_r(errnum, buf, buflen);
#else
char *err;
/* Fall back to non-thread safe strerror()...its all we can do */
if (buflen < 2)
return 0;
err = strerror(errnum);
/* Can this ever happen? */
if (err == NULL)
return 0;
strncpy(buf, err, buflen - 1);
buf[buflen - 1] = '\0';
return 1;
#endif
}