CryptoSys Home > PKI > Portugal DGCI Billing Software Certification (1st version)

Portugal DGCI Billing Software Certification (1st version)


This is the first version of a page we wrote in August 2010 about the Billing Software Certification (Certificação de Software Facturação) scheme introduced by the Portugal General Directorate of Taxes (Direcção Geral dos Impostos) (DGCI) in June 2010 [ESPECIF-2010]. We pointed out the problems that are guaranteed to arise in using the OpenSSL software in the manner suggested, as well as apparent errors in the test vectors provided.

Most of the points raised here were sorted out by the publication of Addendum 1 by the DGCI [ADIT-2010]. We'll leave the relevant parts here that point out the problems in the DGCI's first unamended version. At the end we summarise the Conclusions from Addendum 1.

The latest version of this page is at Portugal DGCI Billing Software Certification (2nd version). That new page includes examples of how to create signatures "properly" using the updated test vectors from DGCI [2010]. Here's the core of what we said last time.


Introduction

We use the only techical reference document we can find from the DGCI as of the date [2010] we are writing this, Especificação das Regras Técnicas para Certificação de Software (Rules of Specification Techniques for Software Certification) [ESPICIF-2010]. This is available from the DGCI web site.

The general idea

A sample base record is

18/05/2010;2010-05-18T11:22:19;FAC 001/14;3:12;

This string is signed using the RSA algorithm and the user's private key. The output is a 172-character string of base64 characters that might look like "Am1K5+CP4LDNVDZYvcLYGpnu8/1b+W ... mgb/kpU=". A base64 string consists of the characters [a-zA-Z0-9/+] terminated by none, one or two "=" padding characters. The length should always be divisible by four.

This base64 string is appended to the second record (note the different time and sequence number) as follows

2010-05-18;2010-05-18T15:43:25;FAC 001/15;25.62;Am1K5+CP4LDNVDZY ... mgb/kpU=

and this second string is signed again with the private key. The output is another 172-character base64-encoded string, say, "XRMQW8CTz2WDczHVsieb+0T1 ... 52wQo8o51dmNeWM="

Note that the document refers to these base64 signature strings incorrectly as a "HASH".

The value of the signature depends on the exact bytes input to the RSA signature algorithm. Add an extra character and you will get a completely different signature value. That's the whole idea of a digital signature. The person verifying the signature must be able to reproduce the exact same sequence of bytes used to create the signature. If they cannot do that the signature will fail.

The big problem in using OpenSSL in the manner shown

OpenSSL is a freely available cryptographic package designed and implemented by experts. It is designed to be used from the command line. This is not a criticism of OpenSSL. The problem is that DGCI recommend a method of using it that is guaranteed to cause problems.

Here is how the document specifies you should create a signature

cmd> echo "2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12;" | openssl dgst -sha1 -sign ChavePrivada.pem | openssl enc -base64	
The problem is using the 'echo' command to pass the string-to-be-signed to the OpenSSL signature routine. You would think that this command is passing the exact string of 47 characters to be signed
2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12;
or in hex notation the 47 bytes
32 30 31 30 2D 30 35 2D 31 38 3B 32 30 31 30 2D 30 35 2D 31 38 54 31 31 3A 32 32 3A 31 39 3B 46 41 43 20 30 30 31 2F 31 34 3B 33 2E 31 32 3B

But it's not. In Windows, the quote characters (") are passed as well, as is the space between the closing quote and the pipe symbol (|), and then Windows adds a CR-LF pair as well. If the user adds any extra spaces between the 'echo' and the opening quote, these spaces will be included as well, as will any additional spaces between the closing quote and the | symbol.

So the actual input to the signature algorithm in this case is
(quote)2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12;(quote)(space)(CR)(LF)
that is the 52 bytes
22 32 30 31 30 2D 30 35 2D 31 38 3B 32 30 31 30 2D 30 35 2D 31 38 54 31 31 3A 32 32 3A 31 39 3B 46 41 43 20 30 30 31 2F 31 34 3B 33 2E 31 32 3B 22 20 13 10

So the signature will be different. Add any extra spaces and you will get a different signature again.

In fact, in the example given in the document, they incorrectly (?) include an extra space between the final ";" and the closing quote ("), so the result is different again. And this is not just a typesetting error because it is carried over to the example signature they give.

Why it is a big problem

Remember that to verify the signature, the recipient must be able to recreate the input string exactly as a sequence of bytes. How is the recipient to know what extra spaces were added accidentally? If a software designer is using another cryptography package to create the signature, should they add all the extra crap that the Windows 'echo' command adds?

Even worse, the behaviour of the 'echo' command is different on a Linux system (it merely adds an extra LF character), so if a user creates a signature using the same command on a Linux system, they will get a completely different signature, and it will fail to validate on a Windows system.

The help notes for GnuWin32 OpenSSL warn about this unexpected behaviour. The correct way should be to create a text file with the exact characters in it and use that as input to the OpenSSL signature algorithm.

The other errors in the document

The specification document [ESPICIF-2010] gives what appear to be only available test vectors for this system. It has some obvious errors. Granted it is difficult to write a PDF document that includes long complicated strings intended be entered on a single command-line. Typesetting considerations often introduce extra spaces. But there are some glaring errors which are faithfully reproduced in the example signatures they give. These are in addition to the problems with the 'echo' command discussed above.

  1. In section 6.1, 1º Registo, they include what appears to be an accidental space character between the final ";" and the closing quote (").
    cmd> echo "2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12; " | openssl dgst -sha1 -sign ChavePrivada.pem | openssl enc -base64
                                                              ^
    
    This may be deliberate and may be intended, we don't know. But it appears inconsistent with the specification in section 4.
  2. In section 6.1, 2º Registo, we have three apparent errors
    cmd> echo "2010-05-18; 2010-05-18T15:43:25;FAC001/15;25.62; Am1K5+CP4LDNVDZYvcLYGpnu8/1b+WWkzgoe8sbZhvk6QFzFvNN77Zsq+cHNm52jCVSEDgWLGHgPS1wcT8ZG7w6KgVq+2/VgOU+xKNt0lcC3gouyarZvcZpZclIReDgLh6m3nv8DYYHKAOQc+eCi/BQ4LqUnuJrca+7emgb/kpU=" | openssl dgst -sha1 -sign ChavePrivada.pem | openssl enc -base64                                                          ^
                          ^                       ^            ^
    
    There is an extra space after the first ";", the mandatory space in "FAC 001" is missed out, and an extra space is added after the final ";". All these errors are in contradiction of the specifications given in the document.

These could be errors introduced during typesetting, but no, the exact same mistakes are carried over and reproduced exactly in the signatures they give.


Conclusions from Addendum 1

  1. Yes, they were typos.
  2. The signature values shown were "illustrative"; in other words, not valid test vectors. See correct values below.
  3. The correct way to concatenate the input (InvoiceDate, SystemEntryDate, InvoiceNo, GrossTotal and Hash) is to use the separator ";" between each of the fields; no extra spaces; no quotation marks; and no extra CR or LF characters.
  4. If you use the `echo` command as suggested, OpenSSL will work properly on a Linux machine (provided you use the correct -A and -N options), but you cannot create a valid signature on a Windows machine using `echo`. However, see our comment above about using a file as input instead.
  5. Do not include any line breaks in the base64-encoded signature value (use the -L option in OpenSSL).

Anyway, thanks to the DGCI for promptly releasing a clarification and some decent test vectors.

Correct Values

  1. In section 6.1, 1º Registo, the correct input to the signature process should be the 47 bytes
    2010-05-18;2010-05-18T11:22:19;FAC 001/14;3.12;
    
    and the resulting signature using the sample DGCI private key Chave_Privada.txt is
    OpE9IFpK5cJO8SwC5BUy3XTCkjVK5JsjHo3TvWjM9D09aw9wabH+sGNOs7hx4iEoOP9UY6DGsR6PgIkAZSTYInhbgs2x9sxWkr417aCKoSGY4awDIVB9aUlQ91SseH3Hk5S24PfjXFDn44acWhQL4INp9Re+dC51YNC7MrpAmP4=
    
  2. In section 6.1, 1º Registo, the correct input to the signature process should be the 220 bytes
    2010-05-18;2010-05-18T15:43:25;FAC 001/15;25.62;Am1K5+CP4LDNVDZYvcLYGpnu8/1b+WWkzgoe8sbZhvk6QFzFvNN77Zsq+cHNm52jCVSEDgWLGHgPS1wcT8ZG7w6KgVq+2/VgOU+xKNt0lcC3gouyarZvcZpZclIReDgLh6m3nv8DYYHKAOQc+eCi/BQ4LqUnuJrca+7emgb/kpU=
    
    and the resulting signature is
    hsR2TYJtl0mad+zVAhGxNLxs6matD+T8Y8IpEo12I3szSohdwwWVOfPclnu6D23pZ0w8g/Eh0TOMzYNsdkkUJpM68/nKH2d8ehI8HT85NUyLgrGhC8msXHK+ASCCOU0RN4mr04249IG+MuOAlnW8EcMJNZA+lTf94MbpJNqRYUw=
    

There is code in VB6/VB200x to reproduce these signature values using CryptoSys PKI on Portugal DGCI Billing Software Certification (2nd version).

References

This page first published by DI Management 7 August 2010. Last updated 15 August 2025.