Merge pull request #4926 from cconlon/namePrintRFC5523

pull/4972/head
Hayden Roche 2022-03-18 15:53:07 -07:00 committed by GitHub
commit 2637e5e361
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 269 additions and 60 deletions

192
src/ssl.c
View File

@ -49613,7 +49613,6 @@ int wolfSSL_sk_X509_NAME_set_cmp_func(WOLF_STACK_OF(WOLFSSL_X509_NAME)* sk,
#ifndef NO_BIO #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 /* Helper function for X509_NAME_print_ex. Sets *buf to string for domain
name attribute based on NID. Returns size of buf */ name attribute based on NID. Returns size of buf */
static int get_dn_attr_by_nid(int n, const char** 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; *buf = str;
return len; 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 wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name,
int indent, unsigned long flags) int indent, unsigned long flags)
{ {
#if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) int i, count = 0, len = 0, tmpSz = 0, nameStrSz = 0, escapeSz = 0;
int count = 0, len = 0, totalSz = 0, tmpSz = 0; char* tmp = NULL;
char tmp[ASN_NAME_MAX+1]; char* nameStr = NULL;
char fullName[ASN_NAME_MAX+2];
const char *buf = NULL; const char *buf = NULL;
WOLFSSL_X509_NAME_ENTRY* ne; WOLFSSL_X509_NAME_ENTRY* ne;
WOLFSSL_ASN1_STRING* str; WOLFSSL_ASN1_STRING* str;
#endif char escaped[ASN_NAME_MAX];
int i;
(void)flags;
WOLFSSL_ENTER("wolfSSL_X509_NAME_print_ex"); WOLFSSL_ENTER("wolfSSL_X509_NAME_print_ex");
if ((name == NULL) || (name->sz == 0) || (bio == NULL))
return WOLFSSL_FAILURE;
for (i = 0; i < indent; i++) { for (i = 0; i < indent; i++) {
if (wolfSSL_BIO_write(bio, " ", 1) != 1) if (wolfSSL_BIO_write(bio, " ", 1) != 1)
return WOLFSSL_FAILURE; return WOLFSSL_FAILURE;
} }
if ((name == NULL) || (name->sz == 0)) count = wolfSSL_X509_NAME_entry_count(name);
return WOLFSSL_FAILURE;
#if defined(WOLFSSL_APACHE_HTTPD) || defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) for (i = 0; i < count; i++) {
/* If XN_FLAG_DN_REV is present, print X509_NAME in reverse order */ /* reverse name order for RFC2253 and DN_REV */
if (flags == (XN_FLAG_RFC2253 & ~XN_FLAG_DN_REV)) { if ((flags & XN_FLAG_RFC2253) || (flags & XN_FLAG_DN_REV)) {
fullName[0] = '\0';
count = wolfSSL_X509_NAME_entry_count(name);
for (i = 0; i < count; i++) {
ne = wolfSSL_X509_NAME_get_entry(name, count - i - 1); ne = wolfSSL_X509_NAME_get_entry(name, count - i - 1);
if (ne == NULL) } else {
return WOLFSSL_FAILURE; ne = wolfSSL_X509_NAME_get_entry(name, i);
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;
} }
if (wolfSSL_BIO_write(bio, fullName, totalSz) != totalSz) if (ne == NULL)
return WOLFSSL_FAILURE; return WOLFSSL_FAILURE;
return WOLFSSL_SUCCESS;
} str = wolfSSL_X509_NAME_ENTRY_get_data(ne);
#else if (str == NULL)
if (flags == XN_FLAG_RFC2253) {
if ((name->sz < 3) ||
(wolfSSL_BIO_write(bio, name->name + 1, name->sz - 2)
!= name->sz - 2))
return WOLFSSL_FAILURE; 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; return WOLFSSL_SUCCESS;
} }

View File

@ -29623,6 +29623,142 @@ static void test_wolfSSL_X509_NAME_hash(void)
#endif #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 #ifndef NO_BIO
static void test_wolfSSL_X509_INFO_multiple_info(void) static void test_wolfSSL_X509_INFO_multiple_info(void)
{ {
@ -52579,6 +52715,7 @@ void ApiTest(void)
test_wolfSSL_lhash(); test_wolfSSL_lhash();
test_wolfSSL_X509_NAME(); test_wolfSSL_X509_NAME();
test_wolfSSL_X509_NAME_hash(); test_wolfSSL_X509_NAME_hash();
test_wolfSSL_X509_NAME_print_ex();
#ifndef NO_BIO #ifndef NO_BIO
test_wolfSSL_X509_INFO_multiple_info(); test_wolfSSL_X509_INFO_multiple_info();
test_wolfSSL_X509_INFO(); test_wolfSSL_X509_INFO();