64
64
#include <openssl/bio.h>
65
65
#include <openssl/mem.h>
66
66
67
- #include "charmap.h"
68
67
#include "internal.h"
69
68
70
69
71
- // These flags must be distinct from |ESC_FLAGS| and fit in a byte.
72
-
73
- // Character is a valid PrintableString character
74
- #define CHARTYPE_PRINTABLESTRING 0x10
75
- // Character needs escaping if it is the first character
76
- #define CHARTYPE_FIRST_ESC_2253 0x20
77
- // Character needs escaping if it is the last character
78
- #define CHARTYPE_LAST_ESC_2253 0x40
79
-
80
- #define CHARTYPE_BS_ESC (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253)
81
-
82
- #define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | \
83
- ASN1_STRFLGS_ESC_QUOTE | \
84
- ASN1_STRFLGS_ESC_CTRL | \
85
- ASN1_STRFLGS_ESC_MSB)
70
+ #define ESC_FLAGS \
71
+ (ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_QUOTE | ASN1_STRFLGS_ESC_CTRL | \
72
+ ASN1_STRFLGS_ESC_MSB)
86
73
87
74
static int maybe_write (BIO * out , const void * buf , int len )
88
75
{
89
76
/* If |out| is NULL, ignore the output but report the length. */
90
77
return out == NULL || BIO_write (out , buf , len ) == len ;
91
78
}
92
79
93
- /*
94
- * This function handles display of strings, one character at a time. It is
95
- * passed an unsigned long for each character because it could come from 2 or
96
- * even 4 byte forms.
97
- */
98
-
99
- #define HEX_SIZE (type ) (sizeof(type)*2)
100
-
101
- static int do_esc_char (uint32_t c , unsigned char flags , char * do_quotes ,
102
- BIO * out )
80
+ static int is_control_character (unsigned char c )
103
81
{
104
- unsigned char chflgs , chtmp ;
105
- char tmphex [ HEX_SIZE ( uint32_t ) + 3 ];
82
+ return c < 32 || c == 127 ;
83
+ }
106
84
85
+ static int do_esc_char (uint32_t c , unsigned long flags , char * do_quotes ,
86
+ BIO * out , int is_first , int is_last )
87
+ {
88
+ /* |c| is a |uint32_t| because, depending on |ASN1_STRFLGS_UTF8_CONVERT|,
89
+ * we may be escaping bytes or Unicode codepoints. */
90
+ char buf [16 ]; /* Large enough for "\\W01234567". */
91
+ unsigned char u8 = (unsigned char )c ;
107
92
if (c > 0xffff ) {
108
- BIO_snprintf (tmphex , sizeof tmphex , "\\W%08" PRIX32 , c );
109
- if (!maybe_write (out , tmphex , 10 ))
110
- return -1 ;
111
- return 10 ;
112
- }
113
- if (c > 0xff ) {
114
- BIO_snprintf (tmphex , sizeof tmphex , "\\U%04" PRIX32 , c );
115
- if (!maybe_write (out , tmphex , 6 ))
116
- return -1 ;
117
- return 6 ;
118
- }
119
- chtmp = (unsigned char )c ;
120
- if (chtmp > 0x7f )
121
- chflgs = flags & ASN1_STRFLGS_ESC_MSB ;
122
- else
123
- chflgs = char_type [chtmp ] & flags ;
124
- if (chflgs & CHARTYPE_BS_ESC ) {
125
- /* If we don't escape with quotes, signal we need quotes */
126
- if (chflgs & ASN1_STRFLGS_ESC_QUOTE ) {
127
- if (do_quotes )
128
- * do_quotes = 1 ;
129
- if (!maybe_write (out , & chtmp , 1 ))
130
- return -1 ;
131
- return 1 ;
93
+ BIO_snprintf (buf , sizeof (buf ), "\\W%08" PRIX32 , c );
94
+ } else if (c > 0xff ) {
95
+ BIO_snprintf (buf , sizeof (buf ), "\\U%04" PRIX32 , c );
96
+ } else if ((flags & ASN1_STRFLGS_ESC_MSB ) && c > 0x7f ) {
97
+ BIO_snprintf (buf , sizeof (buf ), "\\%02X" , c );
98
+ } else if ((flags & ASN1_STRFLGS_ESC_CTRL ) && is_control_character (c )) {
99
+ BIO_snprintf (buf , sizeof (buf ), "\\%02X" , c );
100
+ } else if (flags & ASN1_STRFLGS_ESC_2253 ) {
101
+ /* See RFC 2253, sections 2.4 and 4. */
102
+ if (c == '\\' || c == '"' ) {
103
+ /* Quotes and backslashes are always escaped, quoted or not. */
104
+ BIO_snprintf (buf , sizeof (buf ), "\\%c" , (int )c );
105
+ } else if (c == ',' || c == '+' || c == '<' || c == '>' || c == ';' ||
106
+ (is_first && (c == ' ' || c == '#' )) ||
107
+ (is_last && (c == ' ' ))) {
108
+ if (flags & ASN1_STRFLGS_ESC_QUOTE ) {
109
+ /* No need to escape, just tell the caller to quote. */
110
+ if (do_quotes != NULL ) {
111
+ * do_quotes = 1 ;
112
+ }
113
+ return maybe_write (out , & u8 , 1 ) ? 1 : -1 ;
114
+ }
115
+ BIO_snprintf (buf , sizeof (buf ), "\\%c" , (int )c );
116
+ } else {
117
+ return maybe_write (out , & u8 , 1 ) ? 1 : -1 ;
132
118
}
133
- if (!maybe_write (out , "\\" , 1 ))
134
- return -1 ;
135
- if (!maybe_write (out , & chtmp , 1 ))
136
- return -1 ;
137
- return 2 ;
138
- }
139
- if (chflgs & (ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB )) {
140
- BIO_snprintf (tmphex , 11 , "\\%02X" , chtmp );
141
- if (!maybe_write (out , tmphex , 3 ))
142
- return -1 ;
143
- return 3 ;
144
- }
145
- /*
146
- * If we get this far and do any escaping at all must escape the escape
147
- * character itself: backslash.
148
- */
149
- if (chtmp == '\\' && flags & ESC_FLAGS ) {
150
- if (!maybe_write (out , "\\\\" , 2 ))
151
- return -1 ;
152
- return 2 ;
119
+ } else if ((flags & ESC_FLAGS ) && c == '\\' ) {
120
+ /* If any escape flags are set, also escape backslashes. */
121
+ BIO_snprintf (buf , sizeof (buf ), "\\%c" , (int )c );
122
+ } else {
123
+ return maybe_write (out , & u8 , 1 ) ? 1 : -1 ;
153
124
}
154
- if (! maybe_write ( out , & chtmp , 1 ))
155
- return -1 ;
156
- return 1 ;
125
+
126
+ int len = strlen ( buf ) ;
127
+ return maybe_write ( out , buf , len ) ? len : - 1 ;
157
128
}
158
129
159
130
/*
@@ -163,7 +134,7 @@ static int do_esc_char(uint32_t c, unsigned char flags, char *do_quotes,
163
134
*/
164
135
165
136
static int do_buf (const unsigned char * buf , int buflen , int encoding ,
166
- int utf8_convert , unsigned char flags , char * quotes , BIO * out )
137
+ int utf8_convert , unsigned long flags , char * quotes , BIO * out )
167
138
{
168
139
/* Reject invalid UCS-4 and UCS-2 lengths without parsing. */
169
140
switch (encoding ) {
@@ -185,10 +156,7 @@ static int do_buf(const unsigned char *buf, int buflen, int encoding,
185
156
const unsigned char * q = buf + buflen ;
186
157
int outlen = 0 ;
187
158
while (p != q ) {
188
- unsigned char orflags = 0 ;
189
- if (p == buf && flags & ASN1_STRFLGS_ESC_2253 ) {
190
- orflags = CHARTYPE_FIRST_ESC_2253 ;
191
- }
159
+ const int is_first = p == buf ;
192
160
/* TODO(davidben): Replace this with |cbs_get_ucs2_be|, etc., to check
193
161
* for invalid codepoints. Before doing that, enforce it in the parser,
194
162
* https://crbug.com/boringssl/427, so these error cases are not
@@ -224,8 +192,7 @@ static int do_buf(const unsigned char *buf, int buflen, int encoding,
224
192
assert (0 );
225
193
return -1 ;
226
194
}
227
- if (p == q && flags & ASN1_STRFLGS_ESC_2253 )
228
- orflags = CHARTYPE_LAST_ESC_2253 ;
195
+ const int is_last = p == q ;
229
196
if (utf8_convert ) {
230
197
unsigned char utfbuf [6 ];
231
198
int utflen ;
@@ -237,14 +204,15 @@ static int do_buf(const unsigned char *buf, int buflen, int encoding,
237
204
* otherwise each character will be > 0x7f and so the
238
205
* character will never be escaped on first and last.
239
206
*/
240
- int len = do_esc_char (utfbuf [i ], flags | orflags , quotes , out );
207
+ int len = do_esc_char (utfbuf [i ], flags , quotes , out , is_first ,
208
+ is_last );
241
209
if (len < 0 ) {
242
210
return -1 ;
243
211
}
244
212
outlen += len ;
245
213
}
246
214
} else {
247
- int len = do_esc_char (c , flags | orflags , quotes , out );
215
+ int len = do_esc_char (c , flags , quotes , out , is_first , is_last );
248
216
if (len < 0 ) {
249
217
return -1 ;
250
218
}
@@ -281,14 +249,14 @@ static int do_hex_dump(BIO *out, unsigned char *buf, int buflen)
281
249
* encoding. This uses the RFC 2253 #01234 format.
282
250
*/
283
251
284
- static int do_dump (unsigned long lflags , BIO * out , const ASN1_STRING * str )
252
+ static int do_dump (unsigned long flags , BIO * out , const ASN1_STRING * str )
285
253
{
286
254
if (!maybe_write (out , "#" , 1 )) {
287
255
return -1 ;
288
256
}
289
257
290
258
/* If we don't dump DER encoding just dump content octets */
291
- if (!(lflags & ASN1_STRFLGS_DUMP_DER )) {
259
+ if (!(flags & ASN1_STRFLGS_DUMP_DER )) {
292
260
int outlen = do_hex_dump (out , str -> data , str -> length );
293
261
if (outlen < 0 ) {
294
262
return -1 ;
@@ -362,13 +330,11 @@ static int string_type_to_encoding(int type) {
362
330
* an error occurred.
363
331
*/
364
332
365
- int ASN1_STRING_print_ex (BIO * out , const ASN1_STRING * str , unsigned long lflags )
333
+ int ASN1_STRING_print_ex (BIO * out , const ASN1_STRING * str , unsigned long flags )
366
334
{
367
- /* Keep a copy of escape flags */
368
- unsigned char flags = (unsigned char )(lflags & ESC_FLAGS );
369
335
int type = str -> type ;
370
336
int outlen = 0 ;
371
- if (lflags & ASN1_STRFLGS_SHOW_TYPE ) {
337
+ if (flags & ASN1_STRFLGS_SHOW_TYPE ) {
372
338
const char * tagname = ASN1_tag2str (type );
373
339
outlen += strlen (tagname );
374
340
if (!maybe_write (out , tagname , outlen ) || !maybe_write (out , ":" , 1 ))
@@ -378,29 +344,29 @@ int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, unsigned long lflags)
378
344
379
345
/* Decide what to do with |str|, either dump the contents or display it. */
380
346
int encoding ;
381
- if (lflags & ASN1_STRFLGS_DUMP_ALL ) {
347
+ if (flags & ASN1_STRFLGS_DUMP_ALL ) {
382
348
/* Dump everything. */
383
349
encoding = -1 ;
384
- } else if (lflags & ASN1_STRFLGS_IGNORE_TYPE ) {
350
+ } else if (flags & ASN1_STRFLGS_IGNORE_TYPE ) {
385
351
/* Ignore the string type and interpret the contents as Latin-1. */
386
352
encoding = MBSTRING_ASC ;
387
353
} else {
388
354
encoding = string_type_to_encoding (type );
389
- if (encoding == -1 && (lflags & ASN1_STRFLGS_DUMP_UNKNOWN ) == 0 ) {
355
+ if (encoding == -1 && (flags & ASN1_STRFLGS_DUMP_UNKNOWN ) == 0 ) {
390
356
encoding = MBSTRING_ASC ;
391
357
}
392
358
}
393
359
394
360
if (encoding == -1 ) {
395
- int len = do_dump (lflags , out , str );
361
+ int len = do_dump (flags , out , str );
396
362
if (len < 0 )
397
363
return -1 ;
398
364
outlen += len ;
399
365
return outlen ;
400
366
}
401
367
402
368
int utf8_convert = 0 ;
403
- if (lflags & ASN1_STRFLGS_UTF8_CONVERT ) {
369
+ if (flags & ASN1_STRFLGS_UTF8_CONVERT ) {
404
370
/* If the string is UTF-8, skip decoding and just interpret it as 1 byte
405
371
* per character to avoid converting twice.
406
372
*
0 commit comments