1

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

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.

  • Thank you for the educational code sample, but what kind of code style standard is that? – Z.T. Jun 30 at 21:43
  • @Z.T: compact ;-} – dave_thompson_085 Jul 2 at 5:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.