mirror of https://github.com/wolfSSL/wolfssl.git
Merge pull request #4926 from cconlon/namePrintRFC5523
commit
2637e5e361
192
src/ssl.c
192
src/ssl.c
|
@ -49613,7 +49613,6 @@ int wolfSSL_sk_X509_NAME_set_cmp_func(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk,
|
|||
|
||||
#ifndef NO_BIO
|
||||
|
||||
#if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
|
||||
/* Helper function for X509_NAME_print_ex. Sets *buf to string for domain
|
||||
name attribute based on NID. Returns size of buf */
|
||||
static int get_dn_attr_by_nid(int n, const char** buf)
|
||||
|
@ -49660,87 +49659,160 @@ static int get_dn_attr_by_nid(int n, const char** buf)
|
|||
*buf = str;
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Escape input string for RFC2253 requirements. The following characters
|
||||
* are escaped with a backslash (\):
|
||||
*
|
||||
* 1. A space or '#' at the beginning of the string
|
||||
* 2. A space at the end of the string
|
||||
* 3. One of: ",", "+", """, "\", "<", ">", ";"
|
||||
*
|
||||
* in - input string to escape
|
||||
* inSz - length of in, not including the null terminator
|
||||
* out - buffer for output string to be written, will be null terminated
|
||||
* outSz - size of out
|
||||
*
|
||||
* Returns size of output string (not counting NULL terminator) on success,
|
||||
* negative on error.
|
||||
*/
|
||||
static int wolfSSL_EscapeString_RFC2253(char* in, word32 inSz,
|
||||
char* out, word32 outSz)
|
||||
{
|
||||
word32 inIdx = 0;
|
||||
word32 outIdx = 0;
|
||||
char c = 0;
|
||||
|
||||
if (in == NULL || out == NULL || inSz == 0 || outSz == 0) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
for (inIdx = 0; inIdx < inSz; inIdx++) {
|
||||
|
||||
c = in[inIdx];
|
||||
|
||||
if (((inIdx == 0) && (c == ' ' || c == '#')) ||
|
||||
((inIdx == (inSz-1)) && (c == ' ')) ||
|
||||
c == ',' || c == '+' || c == '"' || c == '\\' ||
|
||||
c == '<' || c == '>' || c == ';') {
|
||||
|
||||
if (outIdx > (outSz - 1)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
out[outIdx] = '\\';
|
||||
outIdx++;
|
||||
}
|
||||
if (outIdx > (outSz - 1)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
out[outIdx] = c;
|
||||
outIdx++;
|
||||
}
|
||||
|
||||
/* null terminate out */
|
||||
if (outIdx > (outSz -1)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
out[outIdx] = '\0';
|
||||
|
||||
return outIdx;
|
||||
}
|
||||
|
||||
/*
|
||||
* The BIO output of wolfSSL_X509_NAME_print_ex does NOT include the null terminator
|
||||
* Print human readable version of X509_NAME to provided BIO.
|
||||
*
|
||||
* bio - output BIO to place name string. Does not include null terminator.
|
||||
* name - input name to convert to string
|
||||
* indent - number of indent spaces to prepend to name string
|
||||
* flags - flags to control function behavior. Not all flags are currently
|
||||
* supported/implemented. Currently supported are:
|
||||
* XN_FLAG_RFC2253 - only the backslash escape requirements from
|
||||
* RFC22523 currently implemented.
|
||||
* XN_FLAG_DN_REV - print name reversed. Automatically done by
|
||||
* XN_FLAG_RFC2253.
|
||||
*
|
||||
* Returns WOLFSSL_SUCCESS (1) on success, WOLFSSL_FAILURE (0) on failure.
|
||||
*/
|
||||
int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name,
|
||||
int indent, unsigned long flags)
|
||||
{
|
||||
#if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
|
||||
int count = 0, len = 0, totalSz = 0, tmpSz = 0;
|
||||
char tmp[ASN_NAME_MAX+1];
|
||||
char fullName[ASN_NAME_MAX+2];
|
||||
int i, count = 0, len = 0, tmpSz = 0, nameStrSz = 0, escapeSz = 0;
|
||||
char* tmp = NULL;
|
||||
char* nameStr = NULL;
|
||||
const char *buf = NULL;
|
||||
WOLFSSL_X509_NAME_ENTRY* ne;
|
||||
WOLFSSL_ASN1_STRING* str;
|
||||
#endif
|
||||
int i;
|
||||
(void)flags;
|
||||
char escaped[ASN_NAME_MAX];
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_X509_NAME_print_ex");
|
||||
|
||||
if ((name == NULL) || (name->sz == 0) || (bio == NULL))
|
||||
return WOLFSSL_FAILURE;
|
||||
|
||||
for (i = 0; i < indent; i++) {
|
||||
if (wolfSSL_BIO_write(bio, " ", 1) != 1)
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
if ((name == NULL) || (name->sz == 0))
|
||||
return WOLFSSL_FAILURE;
|
||||
count = wolfSSL_X509_NAME_entry_count(name);
|
||||
|
||||
#if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
|
||||
/* If XN_FLAG_DN_REV is present, print X509_NAME in reverse order */
|
||||
if (flags == (XN_FLAG_RFC2253 & ~XN_FLAG_DN_REV)) {
|
||||
fullName[0] = '\0';
|
||||
count = wolfSSL_X509_NAME_entry_count(name);
|
||||
for (i = 0; i < count; i++) {
|
||||
for (i = 0; i < count; i++) {
|
||||
/* reverse name order for RFC2253 and DN_REV */
|
||||
if ((flags & XN_FLAG_RFC2253) || (flags & XN_FLAG_DN_REV)) {
|
||||
ne = wolfSSL_X509_NAME_get_entry(name, count - i - 1);
|
||||
if (ne == NULL)
|
||||
return WOLFSSL_FAILURE;
|
||||
|
||||
str = wolfSSL_X509_NAME_ENTRY_get_data(ne);
|
||||
if (str == NULL)
|
||||
return WOLFSSL_FAILURE;
|
||||
|
||||
len = get_dn_attr_by_nid(ne->nid, &buf);
|
||||
if (len == 0 || buf == NULL)
|
||||
return WOLFSSL_FAILURE;
|
||||
|
||||
tmpSz = str->length + len + 2; /* + 2 for '=' and comma */
|
||||
if (tmpSz > ASN_NAME_MAX) {
|
||||
WOLFSSL_MSG("Size greater than ASN_NAME_MAX");
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
if (i < count - 1) {
|
||||
/* tmpSz+1 for last null char */
|
||||
XSNPRINTF(tmp, tmpSz+1, "%s=%s,", buf, str->data);
|
||||
XSTRNCAT(fullName, tmp, tmpSz+1);
|
||||
}
|
||||
else {
|
||||
XSNPRINTF(tmp, tmpSz, "%s=%s", buf, str->data);
|
||||
XSTRNCAT(fullName, tmp, tmpSz-1);
|
||||
tmpSz--; /* Don't include null char in tmpSz */
|
||||
}
|
||||
totalSz += tmpSz;
|
||||
} else {
|
||||
ne = wolfSSL_X509_NAME_get_entry(name, i);
|
||||
}
|
||||
if (wolfSSL_BIO_write(bio, fullName, totalSz) != totalSz)
|
||||
if (ne == NULL)
|
||||
return WOLFSSL_FAILURE;
|
||||
return WOLFSSL_SUCCESS;
|
||||
}
|
||||
#else
|
||||
if (flags == XN_FLAG_RFC2253) {
|
||||
if ((name->sz < 3) ||
|
||||
(wolfSSL_BIO_write(bio, name->name + 1, name->sz - 2)
|
||||
!= name->sz - 2))
|
||||
|
||||
str = wolfSSL_X509_NAME_ENTRY_get_data(ne);
|
||||
if (str == NULL)
|
||||
return WOLFSSL_FAILURE;
|
||||
|
||||
if (flags & XN_FLAG_RFC2253) {
|
||||
/* escape string for RFC 2253, ret sz not counting null term */
|
||||
escapeSz = wolfSSL_EscapeString_RFC2253(str->data,
|
||||
str->length, escaped, sizeof(escaped));
|
||||
if (escapeSz < 0)
|
||||
return WOLFSSL_FAILURE;
|
||||
|
||||
nameStr = escaped;
|
||||
nameStrSz = escapeSz;
|
||||
}
|
||||
else {
|
||||
nameStr = str->data;
|
||||
nameStrSz = str->length;
|
||||
}
|
||||
|
||||
/* len is without null terminator */
|
||||
len = get_dn_attr_by_nid(ne->nid, &buf);
|
||||
if (len == 0 || buf == NULL)
|
||||
return WOLFSSL_FAILURE;
|
||||
|
||||
tmpSz = nameStrSz + len + 3; /* + 3 for '=', comma, and '\0' */
|
||||
tmp = (char*)XMALLOC(tmpSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (tmp == NULL) {
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
if (i < count - 1) {
|
||||
XSNPRINTF(tmp, tmpSz, "%s=%s,", buf, nameStr);
|
||||
tmpSz = len + nameStrSz + 2; /* 2 for '=', comma */
|
||||
}
|
||||
else {
|
||||
XSNPRINTF(tmp, tmpSz, "%s=%s", buf, nameStr);
|
||||
tmpSz = len + nameStrSz + 2; /* 2 for '=', '\0' */
|
||||
}
|
||||
|
||||
if (wolfSSL_BIO_write(bio, tmp, tmpSz) != tmpSz) {
|
||||
XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
#endif /* WOLFSSL_APACHE_HTTPD || OPENSSL_ALL || WOLFSSL_NGINX */
|
||||
else {
|
||||
if ((name->sz < 2) ||
|
||||
(wolfSSL_BIO_write(bio, name->name, name->sz - 1) != name->sz - 1))
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
return WOLFSSL_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
137
tests/api.c
137
tests/api.c
|
@ -29623,6 +29623,142 @@ static void test_wolfSSL_X509_NAME_hash(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void test_wolfSSL_X509_NAME_print_ex(void)
|
||||
{
|
||||
#if (defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \
|
||||
(defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \
|
||||
defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \
|
||||
defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB)))) && \
|
||||
!defined(NO_BIO)
|
||||
int memSz;
|
||||
byte* mem = NULL;
|
||||
BIO* bio = NULL;
|
||||
BIO* membio = NULL;
|
||||
X509* x509 = NULL;
|
||||
X509_NAME* name = NULL;
|
||||
|
||||
const char* expNormal = "C=US,CN=wolfssl.com";
|
||||
const char* expReverse = "CN=wolfssl.com,C=US";
|
||||
|
||||
const char* expNotEscaped = "C= US,+\"\\ ,CN=#wolfssl.com<>;";
|
||||
const char* expNotEscapedRev = "CN=#wolfssl.com<>;,C= US,+\"\\ ";
|
||||
const char* expRFC5523 =
|
||||
"CN=\\#wolfssl.com\\<\\>\\;,C=\\ US\\,\\+\\\"\\\\\\ ";
|
||||
|
||||
printf(testingFmt, "wolfSSL_X509_NAME_print_ex");
|
||||
|
||||
/* Test with real cert (svrCertFile) first */
|
||||
AssertNotNull(bio = BIO_new(BIO_s_file()));
|
||||
AssertIntGT(BIO_read_filename(bio, svrCertFile), 0);
|
||||
AssertNotNull(PEM_read_bio_X509(bio, &x509, NULL, NULL));
|
||||
AssertNotNull(name = X509_get_subject_name(x509));
|
||||
|
||||
/* Test without flags */
|
||||
AssertNotNull(membio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(X509_NAME_print_ex(membio, name, 0, 0), WOLFSSL_SUCCESS);
|
||||
BIO_free(membio);
|
||||
|
||||
/* Test flag: XN_FLAG_RFC2253 */
|
||||
AssertNotNull(membio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(X509_NAME_print_ex(membio, name, 0,
|
||||
XN_FLAG_RFC2253), WOLFSSL_SUCCESS);
|
||||
BIO_free(membio);
|
||||
|
||||
/* Test flag: XN_FLAG_RFC2253 | XN_FLAG_DN_REV */
|
||||
AssertNotNull(membio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(X509_NAME_print_ex(membio, name, 0,
|
||||
XN_FLAG_RFC2253 | XN_FLAG_DN_REV), WOLFSSL_SUCCESS);
|
||||
BIO_free(membio);
|
||||
|
||||
X509_free(x509);
|
||||
BIO_free(bio);
|
||||
|
||||
/* Test normal case without escaped characters */
|
||||
{
|
||||
/* Create name: "/C=US/CN=wolfssl.com" */
|
||||
AssertNotNull(name = X509_NAME_new());
|
||||
AssertIntEQ(X509_NAME_add_entry_by_txt(name, "countryName",
|
||||
MBSTRING_UTF8, (byte*)"US", 2, -1, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
AssertIntEQ(X509_NAME_add_entry_by_txt(name, "commonName",
|
||||
MBSTRING_UTF8, (byte*)"wolfssl.com", 11, -1, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
/* Test without flags */
|
||||
AssertNotNull(membio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(X509_NAME_print_ex(membio, name, 0, 0), WOLFSSL_SUCCESS);
|
||||
AssertIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0);
|
||||
AssertIntEQ(memSz, XSTRLEN(expNormal)+1);
|
||||
AssertIntEQ(XSTRNCMP((char*)mem, expNormal, XSTRLEN(expNormal)), 0);
|
||||
BIO_free(membio);
|
||||
|
||||
/* Test flags: XN_FLAG_RFC2253 - should be reversed */
|
||||
AssertNotNull(membio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(X509_NAME_print_ex(membio, name, 0,
|
||||
XN_FLAG_RFC2253), WOLFSSL_SUCCESS);
|
||||
AssertIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0);
|
||||
AssertIntEQ(memSz, XSTRLEN(expReverse)+1);
|
||||
BIO_free(membio);
|
||||
|
||||
/* Test flags: XN_FLAG_DN_REV - reversed */
|
||||
AssertNotNull(membio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(X509_NAME_print_ex(membio, name, 0,
|
||||
XN_FLAG_DN_REV), WOLFSSL_SUCCESS);
|
||||
AssertIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0);
|
||||
AssertIntEQ(memSz, XSTRLEN(expReverse)+1);
|
||||
AssertIntEQ(XSTRNCMP((char*)mem, expReverse, XSTRLEN(expReverse)), 0);
|
||||
BIO_free(membio);
|
||||
|
||||
X509_NAME_free(name);
|
||||
}
|
||||
|
||||
/* Test RFC2253 characters are escaped with backslashes */
|
||||
{
|
||||
AssertNotNull(name = X509_NAME_new());
|
||||
AssertIntEQ(X509_NAME_add_entry_by_txt(name, "countryName",
|
||||
/* space at beginning and end, and: ,+"\ */
|
||||
MBSTRING_UTF8, (byte*)" US,+\"\\ ", 8, -1, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
AssertIntEQ(X509_NAME_add_entry_by_txt(name, "commonName",
|
||||
/* # at beginning, and: <>;*/
|
||||
MBSTRING_UTF8, (byte*)"#wolfssl.com<>;", 15, -1, 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
/* Test without flags */
|
||||
AssertNotNull(membio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(X509_NAME_print_ex(membio, name, 0, 0), WOLFSSL_SUCCESS);
|
||||
AssertIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0);
|
||||
AssertIntEQ(memSz, XSTRLEN(expNotEscaped)+1);
|
||||
AssertIntEQ(XSTRNCMP((char*)mem, expNotEscaped,
|
||||
XSTRLEN(expNotEscaped)), 0);
|
||||
BIO_free(membio);
|
||||
|
||||
/* Test flags: XN_FLAG_RFC5523 - should be reversed and escaped */
|
||||
AssertNotNull(membio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(X509_NAME_print_ex(membio, name, 0,
|
||||
XN_FLAG_RFC2253), WOLFSSL_SUCCESS);
|
||||
AssertIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0);
|
||||
AssertIntEQ(memSz, XSTRLEN(expRFC5523)+1);
|
||||
AssertIntEQ(XSTRNCMP((char*)mem, expRFC5523, XSTRLEN(expRFC5523)), 0);
|
||||
BIO_free(membio);
|
||||
|
||||
/* Test flags: XN_FLAG_DN_REV - reversed but not escaped */
|
||||
AssertNotNull(membio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(X509_NAME_print_ex(membio, name, 0,
|
||||
XN_FLAG_DN_REV), WOLFSSL_SUCCESS);
|
||||
AssertIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0);
|
||||
AssertIntEQ(memSz, XSTRLEN(expNotEscapedRev)+1);
|
||||
AssertIntEQ(XSTRNCMP((char*)mem, expNotEscapedRev,
|
||||
XSTRLEN(expNotEscapedRev)), 0);
|
||||
BIO_free(membio);
|
||||
|
||||
X509_NAME_free(name);
|
||||
}
|
||||
|
||||
printf(resultFmt, passed);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NO_BIO
|
||||
static void test_wolfSSL_X509_INFO_multiple_info(void)
|
||||
{
|
||||
|
@ -52579,6 +52715,7 @@ void ApiTest(void)
|
|||
test_wolfSSL_lhash();
|
||||
test_wolfSSL_X509_NAME();
|
||||
test_wolfSSL_X509_NAME_hash();
|
||||
test_wolfSSL_X509_NAME_print_ex();
|
||||
#ifndef NO_BIO
|
||||
test_wolfSSL_X509_INFO_multiple_info();
|
||||
test_wolfSSL_X509_INFO();
|
||||
|
|
Loading…
Reference in New Issue