diff --git a/src/x509.c b/src/x509.c index 55967dc5c15..cf4d0815e6c 100644 --- a/src/x509.c +++ b/src/x509.c @@ -15601,61 +15601,73 @@ static int get_dn_attr_by_nid(int n, const char** buf) return len; } -/** - * 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: ",", "+", """, "\", "<", ">", ";" +/* Escape a name entry value. Mirrors OpenSSL's do_esc_char() for single + * byte characters. Only ASN1_STRFLGS_ESC_2253, ASN1_STRFLGS_ESC_CTRL and + * ASN1_STRFLGS_ESC_MSB are implemented. ASN1_STRFLGS_ESC_QUOTE does not + * quote but, as in OpenSSL, still causes the backslash to be escaped. * - * 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 + * in - value to escape, may contain NUL bytes + * inSz - length of in + * flags - ASN1_STRFLGS_* flags + * out - buffer for escaped value, NULL to only get the length * - * Returns size of output string (not counting NULL terminator) on success, - * negative on error. + * Returns number of bytes written, or needed when out is NULL. */ -static int wolfSSL_EscapeString_RFC2253(char* in, word32 inSz, - char* out, word32 outSz) +static int wolfssl_x509_name_esc_value(const char* in, int inSz, + unsigned long flags, char* out) { - word32 inIdx = 0; - word32 outIdx = 0; - - if (in == NULL || out == NULL || inSz == 0 || outSz == 0) { - return BAD_FUNC_ARG; - } - - for (inIdx = 0; inIdx < inSz; inIdx++) { + static const char hexDigit[] = "0123456789ABCDEF"; + const unsigned long escFlags = WOLFSSL_ASN1_STRFLGS_ESC_2253 | + WOLFSSL_ASN1_STRFLGS_ESC_CTRL | WOLFSSL_ASN1_STRFLGS_ESC_MSB | + WOLFSSL_ASN1_STRFLGS_ESC_QUOTE; + int i; + int outIdx = 0; - char c = in[inIdx]; + for (i = 0; i < inSz; i++) { + unsigned char c = (unsigned char)in[i]; + int hex = 0; + int bs = 0; - if (((inIdx == 0) && (c == ' ' || c == '#')) || - ((inIdx == (inSz-1)) && (c == ' ')) || - c == ',' || c == '+' || c == '"' || c == '\\' || - c == '<' || c == '>' || c == ';') { + if (c >= 0x80) { + hex = (flags & WOLFSSL_ASN1_STRFLGS_ESC_MSB) != 0; + } + else if ((flags & WOLFSSL_ASN1_STRFLGS_ESC_2253) && + (c == ',' || c == '+' || c == '"' || c == '\\' || + c == '<' || c == '>' || c == ';' || + (i == 0 && (c == ' ' || c == '#')) || + (i == inSz - 1 && c == ' '))) { + bs = 1; + } + else if ((flags & WOLFSSL_ASN1_STRFLGS_ESC_CTRL) && + (c < 0x20 || c == 0x7F)) { + hex = 1; + } + else if (c == '\\' && (flags & escFlags)) { + /* Any escaping means the escape character itself is escaped. */ + bs = 1; + } - if (outIdx > (outSz - 1)) { - return BUFFER_E; + if (hex) { + if (out != NULL) { + out[outIdx] = '\\'; + out[outIdx + 1] = hexDigit[c >> 4]; + out[outIdx + 2] = hexDigit[c & 0x0F]; } - out[outIdx] = '\\'; - outIdx++; + outIdx += 3; } - if (outIdx > (outSz - 1)) { - return BUFFER_E; + else { + if (bs) { + if (out != NULL) + out[outIdx] = '\\'; + outIdx++; + } + if (out != NULL) + out[outIdx] = (char)c; + outIdx++; } - out[outIdx] = c; - outIdx++; } - /* null terminate out */ - if (outIdx > (outSz -1)) { - return BUFFER_E; - } - out[outIdx] = '\0'; - - return (int)outIdx; + return outIdx; } /* @@ -15663,42 +15675,79 @@ static int wolfSSL_EscapeString_RFC2253(char* in, word32 inSz, * * 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. - * XN_FLAG_SPC_EQ - spaces before and after '=' character + * indent - number of indent spaces to prepend to name string, and to every + * line with XN_FLAG_SEP_MULTILINE + * flags - flags to control function behavior, as in OpenSSL: + * XN_FLAG_SEP_COMMA_PLUS, XN_FLAG_SEP_CPLUS_SPC, + * XN_FLAG_SEP_SPLUS_SPC, XN_FLAG_SEP_MULTILINE - entry + * separator, ", " when none is set + * XN_FLAG_FN_SN, XN_FLAG_FN_LN, XN_FLAG_FN_NONE - attribute + * name style, XN_FLAG_FN_OID prints + * short names + * XN_FLAG_FN_ALIGN - pad the attribute name + * XN_FLAG_DN_REV - print name reversed + * XN_FLAG_SPC_EQ - spaces before and after '=' + * ASN1_STRFLGS_ESC_2253 - backslash escape the RFC 2253 + * special characters in values + * ASN1_STRFLGS_ESC_CTRL - escape control characters as \XX + * ASN1_STRFLGS_ESC_MSB - escape bytes above 0x7F as \XX + * Multi-valued RDNs are flattened: their attributes are separated + * like RDNs. * * 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) { - int i, count = 0, nameStrSz = 0, escapeSz = 0; - int eqSpace = 0; - char eqStr[4]; - char* tmp = NULL; - char* nameStr = NULL; - const char *buf = NULL; + int i, count = 0; + int eqSz = 1; + const char* eqStr = "="; + int sepSz = 2; + const char* sep = ", "; + int lineIndent = 0; + int fnOpt; + int fnWidth = 0; WOLFSSL_X509_NAME_ENTRY* ne; WOLFSSL_ASN1_STRING* str; - char escaped[ASN_NAME_MAX]; WOLFSSL_ENTER("wolfSSL_X509_NAME_print_ex"); if ((name == NULL) || (bio == NULL)) return WOLFSSL_FAILURE; - XMEMSET(eqStr, 0, sizeof(eqStr)); + if (indent < 0) + indent = 0; + + switch (flags & WOLFSSL_XN_FLAG_SEP_MASK) { + case WOLFSSL_XN_FLAG_SEP_COMMA_PLUS: + sep = ","; + sepSz = 1; + break; + case WOLFSSL_XN_FLAG_SEP_SPLUS_SPC: + sep = "; "; + sepSz = 2; + break; + case WOLFSSL_XN_FLAG_SEP_MULTILINE: + sep = "\n"; + sepSz = 1; + lineIndent = indent; + break; + default: + /* XN_FLAG_SEP_CPLUS_SPC or no separator flag */ + break; + } + if (flags & WOLFSSL_XN_FLAG_SPC_EQ) { - eqSpace = 2; - XSTRNCPY(eqStr, " = ", 4); + eqStr = " = "; + eqSz = 3; } - else { - XSTRNCPY(eqStr, "=", 4); + + fnOpt = (int)(flags & WOLFSSL_XN_FLAG_FN_MASK); + if (flags & WOLFSSL_XN_FLAG_FN_ALIGN) { + if (fnOpt == WOLFSSL_XN_FLAG_FN_SN) + fnWidth = 10; + else if (fnOpt == WOLFSSL_XN_FLAG_FN_LN) + fnWidth = 25; } for (i = 0; i < indent; i++) { @@ -15709,12 +15758,16 @@ int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name, count = wolfSSL_X509_NAME_entry_count(name); for (i = 0; i < count; i++) { - int len; + const char* attr = NULL; + int attrSz = 0; + int padSz = 0; + int valSz; int tmpSz; + int idx; + int j; + char* tmp; - /* reverse name order for RFC2253 and DN_REV */ - if ((flags & WOLFSSL_XN_FLAG_RFC2253) || - (flags & WOLFSSL_XN_FLAG_DN_REV)) { + if (flags & WOLFSSL_XN_FLAG_DN_REV) { ne = wolfSSL_X509_NAME_get_entry(name, count - i - 1); } else { @@ -15727,67 +15780,69 @@ int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name, if (str == NULL) return WOLFSSL_FAILURE; - if (flags & WOLFSSL_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) + if (fnOpt == WOLFSSL_XN_FLAG_FN_NONE) { + /* no attribute name */ + } +#ifdef OPENSSL_EXTRA + else if (fnOpt == WOLFSSL_XN_FLAG_FN_LN) { + attr = wolfSSL_OBJ_nid2ln(ne->nid); + if (attr == NULL) return WOLFSSL_FAILURE; - - nameStr = escaped; - nameStrSz = escapeSz; + attrSz = (int)XSTRLEN(attr); } +#endif else { - nameStr = str->data; - nameStrSz = str->length; + /* attrSz is without null terminator */ + attrSz = get_dn_attr_by_nid(ne->nid, &attr); + if (attrSz == 0 || attr == NULL) + return WOLFSSL_FAILURE; } + if (attrSz < fnWidth) + padSz = fnWidth - attrSz; - /* len is without null terminator */ - len = get_dn_attr_by_nid(ne->nid, &buf); - if (len == 0 || buf == NULL) + /* escaping can triple the value length */ + if (str->length < 0 || str->length > INT_MAX / 4) return WOLFSSL_FAILURE; - /* + 4 for '=', comma space and '\0'*/ - tmpSz = nameStrSz + len + 4 + eqSpace; - tmp = (char*)XMALLOC(tmpSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (tmp == NULL) { + valSz = wolfssl_x509_name_esc_value(str->data, str->length, flags, + NULL); + + /* attribute, padding, '=', value and separator, +1 for empty */ + tmpSz = attrSz + padSz + eqSz + valSz + sepSz + 1; + tmp = (char*)XMALLOC((size_t)tmpSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) return WOLFSSL_FAILURE; - } + idx = 0; + if (fnOpt != WOLFSSL_XN_FLAG_FN_NONE) { + XMEMCPY(tmp, attr, (size_t)attrSz); + idx = attrSz; + XMEMSET(tmp + idx, ' ', (size_t)padSz); + idx += padSz; + XMEMCPY(tmp + idx, eqStr, (size_t)eqSz); + idx += eqSz; + } + (void)wolfssl_x509_name_esc_value(str->data, str->length, flags, + tmp + idx); + idx += valSz; if (i < count - 1) { - if (XSNPRINTF(tmp, (size_t)tmpSz, "%s%s%s, ", buf, eqStr, nameStr) - >= tmpSz) - { - WOLFSSL_MSG("buffer overrun"); - XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FAILURE; - } - - tmpSz = len + nameStrSz + 3 + eqSpace; /* 3 for '=', comma space */ - } - else { - if (XSNPRINTF(tmp, (size_t)tmpSz, "%s%s%s", buf, eqStr, nameStr) - >= tmpSz) - { - WOLFSSL_MSG("buffer overrun"); - XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_FAILURE; - } - tmpSz = len + nameStrSz + 1 + eqSpace; /* 1 for '=' */ - if (bio->type != WOLFSSL_BIO_FILE && - bio->type != WOLFSSL_BIO_MEMORY) { - ++tmpSz; /* include the terminating null when not writing to a - * file. - */ - } + XMEMCPY(tmp + idx, sep, (size_t)sepSz); + idx += sepSz; } - if (wolfSSL_BIO_write(bio, tmp, tmpSz) != tmpSz) { + if (wolfSSL_BIO_write(bio, tmp, idx) != idx) { XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_FAILURE; } XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (i < count - 1) { + for (j = 0; j < lineIndent; j++) { + if (wolfSSL_BIO_write(bio, " ", 1) != 1) + return WOLFSSL_FAILURE; + } + } } return WOLFSSL_SUCCESS; diff --git a/tests/api/test_ossl_x509_name.c b/tests/api/test_ossl_x509_name.c index c99b781ade3..2d76fd432b3 100644 --- a/tests/api/test_ossl_x509_name.c +++ b/tests/api/test_ossl_x509_name.c @@ -361,11 +361,35 @@ int test_wolfSSL_X509_NAME_print_ex(void) const char* expNormal = "C=US, CN=wolfssl.com"; const char* expEqSpace = "C = US, CN = wolfssl.com"; const char* expReverse = "CN=wolfssl.com, C=US"; + const char* expRFC2253 = "CN=wolfssl.com,C=US"; + const char* expMultiline = + "countryName = US\n" + "commonName = wolfssl.com"; + const char* expMultilineInd = + " countryName = US\n" + " commonName = wolfssl.com"; + const char* expSemi = "C=US; CN=wolfssl.com"; + const char* expNoName = "US, wolfssl.com"; + const char* expLongName = "countryName=US, commonName=wolfssl.com"; + const char* expAligned = "C =US, CN =wolfssl.com"; + const char* expIndent = " C=US, CN=wolfssl.com"; const char* expNotEscaped = "C= US,+\"\\ , CN=#wolfssl.com<>;"; const char* expNotEscapedRev = "CN=#wolfssl.com<>;, C= US,+\"\\ "; - const char* expRFC5523 = - "CN=\\#wolfssl.com\\<\\>\\;, C=\\ US\\,\\+\\\"\\\\\\ "; + const char* expRFC2253Esc = + "CN=\\#wolfssl.com\\<\\>\\;,C=\\ US\\,\\+\\\"\\\\\\ "; + const char* expEscaped = + "C=\\ US\\,\\+\\\"\\\\\\ , CN=\\#wolfssl.com\\<\\>\\;"; + const char* expEscapedComma = + "C=\\ US\\,\\+\\\"\\\\\\ ,CN=\\#wolfssl.com\\<\\>\\;"; + const unsigned char valNul[] = "with\0null"; + const unsigned char expNul[] = "CN=with\0null"; + const char* expNulCtrl = "CN=with\\00null"; + const unsigned char valBs[] = "a\\b"; + const char* expBsCtrl = "CN=a\\\\b"; + const unsigned char valMsb[] = "\xC3\xA9"; + const char* expMsb = "CN=\\C3\\A9"; + const char* expSpace = "CN=\\ "; /* Test with real cert (svrCertFile) first */ ExpectNotNull(bio = BIO_new(BIO_s_file())); @@ -452,12 +476,92 @@ int test_wolfSSL_X509_NAME_print_ex(void) BIO_free(membio); membio = NULL; - /* Test flags: XN_FLAG_RFC2253 - should be reversed */ + /* Test flags: XN_FLAG_RFC2253 - reversed, comma separated */ ExpectNotNull(membio = BIO_new(BIO_s_mem())); ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, XN_FLAG_RFC2253), WOLFSSL_SUCCESS); ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); - ExpectIntEQ(memSz, XSTRLEN(expReverse)); + ExpectIntEQ(memSz, XSTRLEN(expRFC2253)); + ExpectIntEQ(XSTRNCMP((char*)mem, expRFC2253, XSTRLEN(expRFC2253)), 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: XN_FLAG_MULTILINE - one entry per line, long names + * aligned, spaces around '=' */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, XN_FLAG_MULTILINE), + WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expMultiline)); + ExpectIntEQ(XSTRNCMP((char*)mem, expMultiline, XSTRLEN(expMultiline)), + 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: XN_FLAG_MULTILINE with indent - every line indented */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 2, XN_FLAG_MULTILINE), + WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expMultilineInd)); + ExpectIntEQ(XSTRNCMP((char*)mem, expMultilineInd, + XSTRLEN(expMultilineInd)), 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: XN_FLAG_SEP_SPLUS_SPC */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_SPLUS_SPC | ASN1_STRFLGS_ESC_2253 | + ASN1_STRFLGS_UTF8_CONVERT), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expSemi)); + ExpectIntEQ(XSTRNCMP((char*)mem, expSemi, XSTRLEN(expSemi)), 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: XN_FLAG_FN_NONE */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_NONE | + ASN1_STRFLGS_UTF8_CONVERT), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expNoName)); + ExpectIntEQ(XSTRNCMP((char*)mem, expNoName, XSTRLEN(expNoName)), 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: XN_FLAG_FN_LN */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_LN | + ASN1_STRFLGS_UTF8_CONVERT), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expLongName)); + ExpectIntEQ(XSTRNCMP((char*)mem, expLongName, XSTRLEN(expLongName)), + 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: XN_FLAG_FN_SN | XN_FLAG_FN_ALIGN */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN | XN_FLAG_FN_ALIGN | + ASN1_STRFLGS_UTF8_CONVERT), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expAligned)); + ExpectIntEQ(XSTRNCMP((char*)mem, expAligned, XSTRLEN(expAligned)), 0); + BIO_free(membio); + membio = NULL; + + /* Test indent without XN_FLAG_SEP_MULTILINE - only the first line */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 3, + XN_FLAG_SEP_CPLUS_SPC | ASN1_STRFLGS_UTF8_CONVERT), + WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expIndent)); + ExpectIntEQ(XSTRNCMP((char*)mem, expIndent, XSTRLEN(expIndent)), 0); BIO_free(membio); membio = NULL; @@ -496,13 +600,14 @@ int test_wolfSSL_X509_NAME_print_ex(void) BIO_free(membio); membio = NULL; - /* Test flags: XN_FLAG_RFC5523 - should be reversed and escaped */ + /* Test flags: XN_FLAG_RFC2253 - reversed, escaped, comma separated */ ExpectNotNull(membio = BIO_new(BIO_s_mem())); ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, XN_FLAG_RFC2253), WOLFSSL_SUCCESS); ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); - ExpectIntEQ(memSz, XSTRLEN(expRFC5523)); - ExpectIntEQ(XSTRNCMP((char*)mem, expRFC5523, XSTRLEN(expRFC5523)), 0); + ExpectIntEQ(memSz, XSTRLEN(expRFC2253Esc)); + ExpectIntEQ(XSTRNCMP((char*)mem, expRFC2253Esc, + XSTRLEN(expRFC2253Esc)), 0); BIO_free(membio); membio = NULL; @@ -515,6 +620,147 @@ int test_wolfSSL_X509_NAME_print_ex(void) ExpectIntEQ(XSTRNCMP((char*)mem, expNotEscapedRev, XSTRLEN(expNotEscapedRev)), 0); BIO_free(membio); + membio = NULL; + + /* Test flags: ASN1_STRFLGS_ESC_2253 - escaped but not reversed. + * Flags as used by OpenVPN. */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN | + ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_UTF8_CONVERT), + WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expEscaped)); + ExpectIntEQ(XSTRNCMP((char*)mem, expEscaped, XSTRLEN(expEscaped)), 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: XN_FLAG_RFC2253 without XN_FLAG_DN_REV - escaped but + * not reversed */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_RFC2253 & ~XN_FLAG_DN_REV), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expEscapedComma)); + ExpectIntEQ(XSTRNCMP((char*)mem, expEscapedComma, + XSTRLEN(expEscapedComma)), 0); + BIO_free(membio); + membio = NULL; + + X509_NAME_free(name); + name = NULL; + } + + /* Test NUL, control and non-ASCII bytes in values */ + { + ExpectNotNull(name = X509_NAME_new()); + ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "commonName", + MBSTRING_UTF8, valNul, sizeof(valNul) - 1, -1, 0), + WOLFSSL_SUCCESS); + + /* Test without flags - NUL byte is written as is. OpenSSL falls + * back to X509_NAME_print() here and escapes it. */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, 0), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, sizeof(expNul) - 1); + ExpectIntEQ(XMEMCMP(mem, expNul, sizeof(expNul) - 1), 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: ASN1_STRFLGS_ESC_2253 - NUL byte is written as is */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN | + ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_UTF8_CONVERT), + WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, sizeof(expNul) - 1); + ExpectIntEQ(XMEMCMP(mem, expNul, sizeof(expNul) - 1), 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: ASN1_STRFLGS_ESC_CTRL - NUL byte is escaped */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_CPLUS_SPC | ASN1_STRFLGS_ESC_CTRL | + ASN1_STRFLGS_UTF8_CONVERT), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expNulCtrl)); + ExpectIntEQ(XSTRNCMP((char*)mem, expNulCtrl, XSTRLEN(expNulCtrl)), 0); + BIO_free(membio); + membio = NULL; + + X509_NAME_free(name); + name = NULL; + + /* Backslash is escaped whenever any escaping is done */ + ExpectNotNull(name = X509_NAME_new()); + ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "commonName", + MBSTRING_UTF8, valBs, sizeof(valBs) - 1, -1, 0), + WOLFSSL_SUCCESS); + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_CPLUS_SPC | ASN1_STRFLGS_ESC_CTRL | + ASN1_STRFLGS_UTF8_CONVERT), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expBsCtrl)); + ExpectIntEQ(XSTRNCMP((char*)mem, expBsCtrl, XSTRLEN(expBsCtrl)), 0); + BIO_free(membio); + membio = NULL; + X509_NAME_free(name); + name = NULL; + + ExpectNotNull(name = X509_NAME_new()); + ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "commonName", + MBSTRING_UTF8, valMsb, sizeof(valMsb) - 1, -1, 0), + WOLFSSL_SUCCESS); + + /* Test without flags - non-ASCII bytes are written as is */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, 0), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, 3 + sizeof(valMsb) - 1); + ExpectIntEQ(XMEMCMP(mem + 3, valMsb, sizeof(valMsb) - 1), 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: ASN1_STRFLGS_ESC_MSB - non-ASCII bytes are escaped */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_CPLUS_SPC | ASN1_STRFLGS_ESC_MSB | + ASN1_STRFLGS_UTF8_CONVERT), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expMsb)); + ExpectIntEQ(XSTRNCMP((char*)mem, expMsb, XSTRLEN(expMsb)), 0); + BIO_free(membio); + membio = NULL; + + /* Test flags: XN_FLAG_RFC2253 - includes ASN1_STRFLGS_ESC_MSB */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_RFC2253), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expMsb)); + ExpectIntEQ(XSTRNCMP((char*)mem, expMsb, XSTRLEN(expMsb)), 0); + BIO_free(membio); + membio = NULL; + X509_NAME_free(name); + name = NULL; + + /* A lone space is both a leading and a trailing space */ + ExpectNotNull(name = X509_NAME_new()); + ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "commonName", + MBSTRING_UTF8, (const byte*)" ", 1, -1, 0), + WOLFSSL_SUCCESS); + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, + XN_FLAG_SEP_CPLUS_SPC | ASN1_STRFLGS_ESC_2253 | + ASN1_STRFLGS_UTF8_CONVERT), WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expSpace)); + ExpectIntEQ(XSTRNCMP((char*)mem, expSpace, XSTRLEN(expSpace)), 0); + BIO_free(membio); X509_NAME_free(name); } diff --git a/wolfssl/openssl/x509.h b/wolfssl/openssl/x509.h index 5dd01797cc7..a22a46b4ad6 100644 --- a/wolfssl/openssl/x509.h +++ b/wolfssl/openssl/x509.h @@ -50,7 +50,6 @@ #define WOLFSSL_XN_FLAG_FN_SN 0 #define WOLFSSL_XN_FLAG_COMPAT 0 -#define WOLFSSL_XN_FLAG_RFC2253 1 #define WOLFSSL_XN_FLAG_SEP_COMMA_PLUS (1 << 16) #define WOLFSSL_XN_FLAG_SEP_CPLUS_SPC (2 << 16) #define WOLFSSL_XN_FLAG_SEP_SPLUS_SPC (3 << 16) @@ -65,7 +64,19 @@ #define WOLFSSL_XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24) #define WOLFSSL_XN_FLAG_FN_ALIGN (1 << 25) -#define WOLFSSL_XN_FLAG_MULTILINE 0xFFFF +/* wolfSSL_X509_NAME_print_ex() flattens multi-valued RDNs: their attributes + * are separated like RDNs, never with '+'. */ +#define WOLFSSL_XN_FLAG_RFC2253 (WOLFSSL_ASN1_STRFLGS_RFC2253 | \ + WOLFSSL_XN_FLAG_SEP_COMMA_PLUS | \ + WOLFSSL_XN_FLAG_DN_REV | \ + WOLFSSL_XN_FLAG_FN_SN | \ + WOLFSSL_XN_FLAG_DUMP_UNKNOWN_FIELDS) +#define WOLFSSL_XN_FLAG_MULTILINE (WOLFSSL_ASN1_STRFLGS_ESC_CTRL | \ + WOLFSSL_ASN1_STRFLGS_ESC_MSB | \ + WOLFSSL_XN_FLAG_SEP_MULTILINE | \ + WOLFSSL_XN_FLAG_SPC_EQ | \ + WOLFSSL_XN_FLAG_FN_LN | \ + WOLFSSL_XN_FLAG_FN_ALIGN) #define WOLFSSL_XN_FLAG_ONELINE (WOLFSSL_XN_FLAG_SEP_CPLUS_SPC | WOLFSSL_XN_FLAG_SPC_EQ | WOLFSSL_XN_FLAG_FN_SN) #ifndef OPENSSL_COEXIST