Error trying to verify signature on CBOR message

Issue

I’m having problems decoding EU Digital Certificate (“Covid pass”) using COSE-JAVA. Public key appears to load ok but when I try to validate the CBOR message, I get following error:

COSE.CoseException: Signature verification failure
    at COSE.SignCommon.validateSignature(SignCommon.java:205)
    at COSE.Signer.validate(Signer.java:212)
    at COSE.Message.validate(Message.java:288)
Caused by: java.lang.NullPointerException: Attempt to get length of null array
    at COSE.SignCommon.convertConcatToDer(SignCommon.java:212)

Here is code for validation:

public static String DecodeMessage(byte[] data) throws CoseException, CborParseException {
    Message m  Encrypt0Message.DecodeFromBytes(data);

    PublicKey key  getPublicKey("here goes PEM of public key");

    CborMap cborMap  CborMap.createFromCborByteArray(m.GetContent());

    CounterSign signer  new CounterSign();
    signer.setKey(new OneKey(key, null));
    signer.addAttribute(HeaderKeys.Algorithm, AlgorithmID.ECDSA_256.AsCBOR(), Attribute.ProtectedAttributes);

    // error happens here
    m.validate(signer);


    return cborMap.toJsonString();
}

This is how public key is generated from PEM:

    public static PublicKey getPublicKey(String keyData) {
    try
    {
        Security.removeProvider("BC");
        Security.addProvider(new BouncyCastleProvider());
        Reader rdr  new StringReader(
                "-----BEGIN EC PUBLIC KEY-----\n" + keyData + "\n" + "-----END EC PUBLIC KEY-----\n"
        );

        org.bouncycastle.util.io.pem.PemObject spki  new org.bouncycastle.util.io.pem.PemReader(rdr).readPemObject();

        byte[] content  spki.getContent();
        X509EncodedKeySpec pubKeySpec  new X509EncodedKeySpec(content);
        return KeyFactory.getInstance("EC", "BC").generatePublic(pubKeySpec);
    }
    catch (Exception ex)
    {
        return  null;
    }

Public key is defined as:

"publicKeyAlgorithm": {
  "hash": {
    "name": "SHA-256"
  },
  "name": "ECDSA",
  "namedCurve": "P-256"
},
"publicKeyPem": "..."

Here is code for doing same thing in Python, might help someone. Code must work on Android 7.1 (embedded device, no way to upgrade to newer Android).

Solution

Solved…

public static boolean VerifySignature(byte[] data, String publicKey) {
    boolean result  false;
    try {

        Message m  Encrypt0Message.DecodeFromBytes(data);
        Sign1Message sm  (Sign1Message) m;

        PublicKey key  getPublicKey(publicKey);

        if (sm.validate(new OneKey(key, null))) {
            result  true;
        }
    } catch (Exception ex) {
        log.error("Error verifying signature", ex);
    }
    return result;
}

and

    public static PublicKey getPublicKey(String keyData) {
    try {
        Security.removeProvider("BC");
        Security.addProvider(new BouncyCastleProvider());
        Reader rdr  new StringReader(
                "-----BEGIN EC PUBLIC KEY-----\n" + keyData + "\n" + "-----END EC PUBLIC KEY-----\n"
        );

        org.bouncycastle.util.io.pem.PemObject spki  new org.bouncycastle.util.io.pem.PemReader(rdr).readPemObject();

        byte[] content  spki.getContent();
        X509EncodedKeySpec pubKeySpec  new X509EncodedKeySpec(content);
        return KeyFactory.getInstance("EC", "BC").generatePublic(pubKeySpec);
    } catch (Exception ex) {
        return null;
    }
}

Answered By – nighthawk

Leave a Comment