Network Security Services and the Pretty-print / SurprizingFacts utility

The Network Security Services (NSS) package is a collection of libraries used for cross-platform development of secure client and server applications.

The NSS package, as well as OpenSSL, provides the ability to use various PKI functions (key generation, x509v3 certificate issuance, work with electronic signature, TLS support, etc.) command-line utility. One of these utilities, Pretty-print (PP), allows you to view the contents of both the x509 v3 certificate and the electronic signature (pkcs # 7), etc., in a convenient way. At what the certificate can be both in DER, and PEM-encodings:

  bash-4.3 $ pp -h
Usage: pp [-t type] [-a] [-i input] [-o output] [-w] [-u]
Pretty prints a file containing ASN.1 data in DER or ascii format. -t type Specify input and display
              Public-key (pk), certificate (c), certificate-request (cr),
              Certificate-identity (ci), pkcs7 (p7), crl or name (n).
              (Use either the long type name or the shortcut.)
-a Input is in ascii encoded form (RFC1113)
-i input Define an input file to use (default is stdin)
-o output Define an output file to use (default is stdout)
-w Do not wrap long output lines
-u Use UTF-8 (default is to show non-ascii as.)
Bash-4.3 $  

Moreover, the presence of parameter -u (encoding UTF-8) allows you to view the certificate in Russian encoding. But looking closely at the screenshots of the graphical interface to the NSS command-line tool utilities, you notice that part of the certificate data just disappeared:


The search for missing information began. The "nice print" utility (namely, Pretty-print translation) was used to view the root certificate of the Headquarter Center of the Ministry of Communications and Communications at the command line:

  $ pp - certificate -u -i MSC_Minkomsvyazi.cer
       Subject: "CN = Head Identification Center
           , INN = 007710474375, OGRN = 1047702026701, O = Ministry of Communications Р  
           Russia, STREET = "125375 Moscow, Tverskaya Street
           , 7, L = Moscow, ST = 77 Moscow, C = RU, E = dit @ minsvya
           Z.ru "

The received result confirmed the loss of data. Moreover, two non-displayed symbols appeared on the screen (a black diamond with a question mark "inside"). The analysis showed that these non-displayed symbols have the codes 0xD0 and 0xBE, respectively:


The Russian letter "o" with the hexadecimal representation in the UTF-8 encoding as 0xD00xBE was missing. And the codes 0xD0 and 0xBE are our non-displayed symbols. And what kind of characters appeared between these bytes? And this is the "pretty" seal – the symbols for aligning the printed text.

What happened? At the input of "nice" printing (the file /nss/cmd/lib/secutil.c, the function secu_PrintRawStringQuotesOptional) the data comes in the form of SECITEM, i.e. Address to the byte array and its length:

  for (i = 0; i < si-> len; i ++) {
        Unsigned char val = si-> data [i];
        Unsigned char c;
          If (SECU_GetWrapEnabled () && column> 76) {
            SECU_Newline (out);
            SECU_Indent (out, level);
            Column = level * INDENT_MULT;

        If (utf8DisplayEnabled) {
            If (val <32)
                C = '.';
                C = val;
        } Else {
            C = printable [val];
        Fprintf (out, "% c", c);
        Column ++;

And if SECA_GetWrapEnabled () == True) nice print (no -w option for the PP utility) and the number of bytes in the string exceeded 76 (column> 76), then after the next character a new line (SECU_Newline) and the necessary indentation (SECU_Indent) are inserted ). At the same time, none of the developers thought that if UTF-8 encoding (utf8DisplayEnabled) is used, then beauty can be imposed only after the next character, and not byte, since the concept of byte and character in UTF-8 encoding may not coincide . If to speak about Russian letters, each of them is coded by two bytes. It was this kind of gap that occurred with our Russian letter "o" (0xD00xBE).

What is the solution? It's very simple to replace the line in the function secu_PrintRawStringQuotesOptional:

  if (SECU_GetWrapEnabled () && column> 76) { 

To the line of the following form:

  if (SECU_GetWrapEnabled () && column> 76 && (val <= 0x7F || val == 0xD0 || val == 0xD1)) { 

If you now reassemble the utility PP and install it into the system, then the "pretty" print will justify its name for "great, powerful, truthful and free Russian language!" (IS Turgenev):


If we talk about the beauty of printing, we could add the transfer not only by the number of characters in the line, but more correct, for example, by space, comma, colon and other symbols. I'm not talking about the semantic analysis in the transfer. But this is already an area of ​​artificial intelligence.

And finally, this is the second detected inaccuracy in NSS utilities. The first was discovered in the utility oidcalc.