2

I am doing active authentication of ePassports according to ICAO 9303 standard (part11).

  1. Send a challenge to the chip, the chip signs it using its private key (stored inside the chip, not readable)
  2. The chip sends the siganture .
  3. You then verify the signature using the public key (can be read from the chip)

There's two possible signature Algorithms: RSA (RSA-SHA1, RSA-PSS, RSA-SHA224, RSA-SHA256, RSA-SHA512) and ECDSA.

In section 6.1.2.3 of ICAO9303 part 11 it reads about ECDSA: " For ECDSA, the plain signature format according to TR-03111 SHALL be used. Only prime curves with uncompressed points SHALL be used. A hash algorithm, whose output length is of the same length or shorter than the length of the ECDSA key in use, SHALL be used."

What I don't quite get is how do I use the ECDSA signature in this plain format with OpenSSL? In the following code EVP_DigestVerifyFinal returns -1. How can I bring the signature oSIG from plain format to DER format?

bool doAA(std::vector<unsigned char> oRND, std::vector<unsigned char> oSIG, std::vector<unsigned char> oPKEY)
{


    EVP_PKEY* m_pPubkey;
    BIO* keyBio = BIO_new_mem_buf(&oPKEY[0], (int)oPKEY.size());
    m_pPubkey = d2i_PUBKEY_bio(keyBio, NULL);       
    BIO_free(keyBio);

    if (NULL == m_pPubkey)
    {
        std::cout << "Error Public key is NULL" << std::endl;
        return false;
    }

    // check if ECDSA signature and then verify
    int nRes = 0;
    int type = EVP_PKEY_base_id(m_pPubkey);
    if (type == EVP_PKEY_EC)
    {
        EVP_MD_CTX* ctx = EVP_MD_CTX_create();

        nRes = EVP_DigestVerifyInit(ctx, NULL, EVP_sha1(), NULL, m_pPubkey);
        if (1 != nRes)
        {
            EVP_MD_CTX_cleanup(ctx);
            std::cout << "Error EVP_DigestVerifyInit" << std::endl;
            return false;
        }

        nRes = EVP_DigestVerifyUpdate(ctx, &oRND[0], oRND.size());
        if (1 != nRes)
        {
            EVP_MD_CTX_cleanup(ctx);
            std::cout << "Error EVP_DigestVerifyUpdate" << std::endl;
            return false;
        }

        nRes = EVP_DigestVerifyFinal(ctx, &oSIG[0], oSIG.size());
        EVP_MD_CTX_cleanup(ctx);
        if (nRes < 0)
        {
            std::cout << "Error EVP_DigestVerifyFinal failed" << std::endl;
            return false;
        }
        else if (nRes == 0)
        {
            std::cout << "Error EVP_DigestVerifyFinal: Signature could not be verified" << std::endl;
            return false;
        }



    }
    else
    {
        std::cout << "Not a ECDSA Signature" << std::endl;
        return false;
    }

    return nRes == 1;
}

EDIT: This is the error I get: error:0D07207B:lib(13):func(114):reason(123)

1 Answer 1

3

Since you're already using OpenSSL you can construct an ECDSA_SIG structure and encode it; see https://stackoverflow.com/questions/31390784/creating-a-der-formatted-ecdsa-signature-from-raw-r-and-s .

Or you can write your own DER encoder for this specific case which is fairly simple, although a general ASN.1 encoder is not:

// given int l is the curve-and-field size in octets with l<61 
// (i.e. P-256 or P-384 is okay for this code but P-521 is not) 
// and unsigned char plain [2*l] is the 'plain' signature
unsigned char * der = malloc(2*l+8); // worst case
int o = 2; // offset into 'der' (output)
int s = 0; while(s<l && plain[s]==0) s++; // skip leading zeros in R
int m = plain[s]&0x80 != 0; // need sign byte for R
der[o++]=2; der[o++]=l-s+m; if(m) der[o++]=0; memcpy(der+o, plain+s, l-s); o+=l-s;
s = l; while(s<l*2 && plain[s]==0) s++; // skip leading zeros in S
m = plain[s]&0x80 != 0; // need sign byte for S
der[o++]=2; der[o++]=l*2-s+m; if(m) der[o++]=0; memcpy(der+o, plain+s, l*2-s); o+=l*2-s;
der[0]=0x30; der[1]=o-2;
// use der for length o as the signature buffer
// when done free(der)
// or in C++ use new[] and delete[] if you or your style rules prefer

Edited 2019-07-30; original version didn't handle leading zeros in the fixed-length R,S, which are fairly rare but do happen sometimes.

3
  • 1
    Thank you for the educational code sample, but what kind of code style standard is that?
    – Z.T.
    Commented Jun 30, 2019 at 21:43
  • 2
    @Z.T: compact ;-} Commented Jul 2, 2019 at 5:31
  • You saved my day - especially the leading zeros problem which is mandatory and occurs not so rarely! Commented Feb 17, 2021 at 20:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .