X509_NAME_oneline(): Fix output of multi-valued RDNs, escaping '/' and '+' in values
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Wed, 2 Sep 2020 12:18:34 +0000 (14:18 +0200)
committerDr. David von Oheimb <David.von.Oheimb@siemens.com>
Thu, 10 Sep 2020 10:07:33 +0000 (12:07 +0200)
Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/12769)

crypto/x509/x509_obj.c
doc/man3/X509_NAME_print_ex.pod

index c1e893bf1367b399a4fc1d6c8b53c12781056c4a..7bed79a2d526413cbc028dfbf1f6d99ec3407ccd 100644 (file)
@@ -13,6 +13,7 @@
 #include <openssl/x509.h>
 #include <openssl/buffer.h>
 #include "crypto/x509.h"
+#include "crypto/ctype.h"
 
 DEFINE_STACK_OF(X509_NAME_ENTRY)
 
@@ -28,6 +29,7 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
     const X509_NAME_ENTRY *ne;
     int i;
     int n, lold, l, l1, l2, num, j, type;
+    int prev_set = -1;
     const char *s;
     char *p;
     unsigned char *q;
@@ -109,14 +111,11 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
             if (!gs_doit[j & 3])
                 continue;
             l2++;
-#ifndef CHARSET_EBCDIC
-            if ((q[j] < ' ') || (q[j] > '~'))
-                l2 += 3;
-#else
-            if ((os_toascii[q[j]] < os_toascii[' ']) ||
-                (os_toascii[q[j]] > os_toascii['~']))
+            if (q[j] == '/' || q[j] == '+')
+                l2++; /* char needs to be escaped */
+            else if ((ossl_toascii(q[j]) < ossl_toascii(' ')) ||
+                     (ossl_toascii(q[j]) > ossl_toascii('~')))
                 l2 += 3;
-#endif
         }
 
         lold = l;
@@ -133,7 +132,7 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
             break;
         } else
             p = &(buf[lold]);
-        *(p++) = '/';
+        *(p++) = prev_set == ne->set ? '+' : '/';
         memcpy(p, s, (unsigned int)l1);
         p += l1;
         *(p++) = '=';
@@ -152,8 +151,11 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
                 *(p++) = 'x';
                 *(p++) = hex[(n >> 4) & 0x0f];
                 *(p++) = hex[n & 0x0f];
-            } else
+            } else {
+                if (n == '/' || n == '+')
+                    *(p++) = '\\';
                 *(p++) = n;
+            }
 #else
             n = os_toascii[q[j]];
             if ((n < os_toascii[' ']) || (n > os_toascii['~'])) {
@@ -161,11 +163,15 @@ char *X509_NAME_oneline(const X509_NAME *a, char *buf, int len)
                 *(p++) = 'x';
                 *(p++) = hex[(n >> 4) & 0x0f];
                 *(p++) = hex[n & 0x0f];
-            } else
+            } else {
+                if (n == os_toascii['/'] || n == os_toascii['+'])
+                    *(p++) = '\\';
                 *(p++) = q[j];
+            }
 #endif
         }
         *p = '\0';
+        prev_set = ne->set;
     }
     if (b != NULL) {
         p = b->data;
index e5bdf1d582340ca00eff62030a7faae96647afd3..ccb4b5629ab8b82036551420308447dd6bfcb525 100644 (file)
@@ -18,27 +18,28 @@ X509_NAME_oneline - X509_NAME printing routines
 
 =head1 DESCRIPTION
 
-X509_NAME_print_ex() prints a human readable version of B<nm> to BIO B<out>.
-Each line (for multiline formats) is indented by B<indent> spaces. The
-output format can be extensively customised by use of the B<flags> parameter.
+X509_NAME_print_ex() prints a human readable version of I<nm> to BIO I<out>.
+Each line (for multiline formats) is indented by I<indent> spaces. The
+output format can be extensively customised by use of the I<flags> parameter.
 
 X509_NAME_print_ex_fp() is identical to X509_NAME_print_ex()
-except the output is written to FILE pointer B<fp>.
+except the output is written to FILE pointer I<fp>.
 
-X509_NAME_oneline() prints an ASCII version of B<a> to B<buf>.
-If B<buf> is B<NULL> then a buffer is dynamically allocated and returned, and
-B<size> is ignored.
-Otherwise, at most B<size> bytes will be written, including the ending '\0',
-and B<buf> is returned.
+X509_NAME_oneline() prints an ASCII version of I<a> to I<buf>.
+This supports multi-valued RDNs and escapes B</> and B<+> characters in values.
+If I<buf> is B<NULL> then a buffer is dynamically allocated and returned, and
+I<size> is ignored.
+Otherwise, at most I<size> bytes will be written, including the ending '\0',
+and I<buf> is returned.
 
-X509_NAME_print() prints out B<name> to B<bp> indenting each line by B<obase>
+X509_NAME_print() prints out I<name> to I<bp> indenting each line by I<obase>
 characters. Multiple lines are used if the output (including indent) exceeds
 80 characters.
 
 =head1 NOTES
 
 The functions X509_NAME_oneline() and X509_NAME_print()
-produce a non standard output form, they don't handle multi character fields and
+produce a non standard output form, they don't handle multi-character fields and
 have various quirks and inconsistencies.
 Their use is strongly discouraged in new applications and they could
 be deprecated in a future release.