Occasional error with signatures in DER format from Nitrokey

Hi,
I am getting signatures from a Nitrokey in DER format. I then process those signatures in Python.
I am using python-ecdsa and occasionally it will raise an error because it doesn’t expect a leading zero-byte before an integer that is positive.

Here is an example of a real signature I got from the nitrokey (i have replaced most of each integer with x in order to more easily read the bytes that matter):

30 44
02 20 0059 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
02 20 22B4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Both integers are 32 bytes long. Only the first integer has been prefixed with a zero-byte.

The first byte is 0x30 as expected. And the second byte 0x44 is the correct length for the data.

The first integer starts with 0x0059 - this is what is causing the python library (a call to ecdsa.util.sigdecode_der() function) to throw error UnexpectedDER(“Invalid encoding of integer, unnecessary zero padding bytes”).

My understanding is that the leading-zero should only exist if the next byte does not have it’s most-significant bit set - but 0x59 does not.

I created a test script in order to find this error, so maybe i am extracting the DER signature incorrectly? or maybe the nitrokey and python-ecdsa differ on the DER format? The problem only occurs occasionally - maybe 1 in 250 when i looped the code below.

while (true) {
  var crypto = km.sc.getCrypto();
  var dat = source.key.crypto.generateRandom(32);
  var rawsig = crypto.sign(source.key, Crypto.ECDSA_SHA256, dat);
  var sig = new ByteString(rawsig.toString().replace(/ /g, ""), HEX);

  var xlen = sig.byteAt(3);
  var xbytes = sig.bytes(4, xlen);
  var ylen = sig.byteAt(4 + xlen + 1);
  var ybytes = sig.bytes(6 + xlen, ylen);

  if (xbytes.byteAt(0) == 0x00 && ((xbytes.byteAt(1) & (1 << 7)) == 0) ) {
    throw new Error("Found unneccessary leading zero byte in integer X: " + h);
  }
  if (ybytes.byteAt(0) == 0x00 && ((ybytes.byteAt(1) & (1 << 7)) == 0) ) {
    throw new Error("Found unneccessary leading zero byte in integer Y: " + h);
  }
}

Thanks
Doug

Which Nitrokey model do you use?

Hi,
I didn’t purchase the nitrokey myself and i have no way of getting any order details but the output of “pkcs11-tool -L” is as follows (i’ve removed the serial number):

Slot 0 (0x0): Nitrokey Nitrokey HSM
  token label        : MBS (UserPIN)
  token manufacturer : www.CardContact.de
  token model        : PKCS#15 emulated
  token flags        : login required, rng, token initialized, PIN initialized
  hardware version   : 24.13
  firmware version   : 3.5
  pin min/max        : 6/15

Thanks,
Doug

hey,

that’s interesting, might be worth checking DER specs for this detail, don’t know it from the top of my head.
@sc-hsm @saper do you guys have an idea, especially whether it originates from the smartcard or is this something created on transport level (the MCU)?

That is a known issue of the crypto library in JCOP3. The returned TLV structure may contain ASN.1 Integer with unnecessary leading zeros. Some crypto libraries treat that as an error and refuse verification.

That is the reason why we use

-Dorg.bouncycastle.asn1.allow_unsafe_integer=true

with Bouncycastle.

If you use PKCS#11 that is not an issue, as ECDSA signatures at the API are encoded in R||S format, meaning a fixed length byte string.

The CVC class in OpenSCDP has a rewrapSignature() message that fixes the leading zero.

2 Likes