X.509 Example

From Crypto++ Wiki
Jump to navigation Jump to search

The Crypto++ library does not provide X.509 certificate support. If you need the support, then you have two options. First is the sample code provided below by Geoff Beier. Beier provided the sample code back in 2007. Also see Newbie question: RSA Signature Verification on the cryptopp-users mailing list.

The second option is the X509Certificate class. X509Certificate is a new addition, and it first appeared in September 2019. X509Certificate is not part of the library either, but it is a well supported add-on. Better late then never...

Sample Program

The following was offered by Geoff Beier on the Crypto++ newsgroup.

GetPublicKeyFromCert

/**
 * Reads an X.509 v3 certificate from certin, extracts the subjectPublicKeyInfo structure
 * (which is one way PK_Verifiers can get their key material) and writes it to keyout
 *
 * @throws CryptoPP::BERDecodeError
 */

void GetPublicKeyFromCert(CryptoPP::BufferedTransformation & certin,
    CryptoPP::BufferedTransformation & keyout)
{
       BERSequenceDecoder x509Cert(certin);
       BERSequenceDecoder tbsCert(x509Cert);

       // ASN.1 from RFC 3280
       // TBSCertificate  ::=  SEQUENCE  {
       // version         [0]  EXPLICIT Version DEFAULT v1,

       // consume the context tag on the version
       BERGeneralDecoder context(tbsCert, CONTEXT_SPECIFIC|CONSTRUCTED|0);
       word32 ver;

       // only want a v3 cert
       BERDecodeUnsigned<word32>(context,ver,INTEGER,2,2);

       // serialNumber         CertificateSerialNumber,
       Integer serial;
       serial.BERDecode(tbsCert);

       // signature            AlgorithmIdentifier,
       BERSequenceDecoder signature(tbsCert);
       signature.SkipAll();

       // issuer               Name,
       BERSequenceDecoder issuerName(tbsCert);
       issuerName.SkipAll();

       // validity             Validity,
       BERSequenceDecoder validity(tbsCert);
       validity.SkipAll();

       // subject              Name,
       BERSequenceDecoder subjectName(tbsCert);
       subjectName.SkipAll();

       // subjectPublicKeyInfo SubjectPublicKeyInfo,
       BERSequenceDecoder spki(tbsCert);
       DERSequenceEncoder spkiEncoder(keyout);

       spki.CopyTo(spkiEncoder);
       spkiEncoder.MessageEnd();

       spki.SkipAll();
       tbsCert.SkipAll();
       x509Cert.SkipAll();
}

Harness

And Geoff's test program:

// A very simple test of the above function

// a smart pointer for PK_Verifier so less cleanup is needed if something throws
typedef std::auto_ptr<CryptoPP::PK_Verifier> PK_VerifierPtr;

// Signature Algorithm OIDs commonly used in certs that have RSA keys
DEFINE_OID(CryptoPP::ASN1::pkcs_1()+4, md5withRSAEncryption);
DEFINE_OID(CryptoPP::ASN1::pkcs_1()+5, sha1withRSAEncryption);

// Some test data
// The certificate used by https://mail.google.com/
unsigned char googlecert[] = {
0x30,0x82,0x03,0x21,0x30,0x82,0x02,0x8A,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4B,
0xA5,0xAE,0x59,0xDE,0xDD,0x1C,0xC7,0x80,0x7C,0x89,0x22,0x91,0xF0,0xE2,0x43,0x30,
0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30,0x4C,
0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x5A,0x41,0x31,0x25,0x30,
0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x43,
0x6F,0x6E,0x73,0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x28,0x50,0x74,0x79,0x29,0x20,
0x4C,0x74,0x64,0x2E,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x03,0x13,0x0D,0x54,
0x68,0x61,0x77,0x74,0x65,0x20,0x53,0x47,0x43,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,
0x30,0x36,0x30,0x35,0x31,0x35,0x32,0x33,0x31,0x38,0x31,0x31,0x5A,0x17,0x0D,0x30,
0x37,0x30,0x35,0x31,0x35,0x32,0x33,0x31,0x38,0x31,0x31,0x5A,0x30,0x68,0x31,0x0B,
0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,
0x03,0x55,0x04,0x08,0x13,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,
0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x07,0x13,0x0D,0x4D,0x6F,0x75,0x6E,0x74,
0x61,0x69,0x6E,0x20,0x56,0x69,0x65,0x77,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
0x0A,0x13,0x0A,0x47,0x6F,0x6F,0x67,0x6C,0x65,0x20,0x49,0x6E,0x63,0x31,0x17,0x30,
0x15,0x06,0x03,0x55,0x04,0x03,0x13,0x0E,0x77,0x77,0x77,0x2E,0x67,0x6F,0x6F,0x67,
0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,
0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,
0x81,0x81,0x00,0xE6,0xC5,0xC6,0x8D,0xCD,0x0B,0xA3,0x03,0x04,0xDC,0xAE,0xCC,0xC9,
0x46,0xBE,0xBD,0xCC,0x9D,0xBC,0x73,0x34,0x48,0xFE,0xD3,0x75,0x64,0xD0,0xC9,0xC9,
0x76,0x27,0x72,0x0F,0xA9,0x96,0x1A,0x3B,0x81,0xF3,0x14,0xF6,0xAE,0x90,0x56,0xE7,
0x19,0xD2,0x73,0x68,0xA7,0x85,0xA4,0xAE,0xCA,0x24,0x14,0x30,0x00,0xBA,0xE8,0x36,
0x5D,0x81,0x73,0x3A,0x71,0x05,0x8F,0xB1,0xAF,0x11,0x87,0xDA,0x5C,0xF1,0x3E,0xBF,
0x53,0x51,0x84,0x6F,0x44,0x0E,0xB7,0xE8,0x26,0xD7,0x2F,0xB2,0x6F,0xF2,0xF2,0x5D,
0xDF,0xA7,0xCF,0x8C,0xA5,0xE9,0x1E,0x6F,0x30,0x48,0x94,0x21,0x0B,0x01,0xAD,0xBA,
0x0E,0x71,0x01,0x0D,0x10,0xEF,0xBF,0xEE,0x2C,0xD3,0x8D,0xFE,0x54,0xA8,0xFE,0xD3,
0x97,0x8F,0xCB,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xE7,0x30,0x81,0xE4,0x30,0x28,
0x06,0x03,0x55,0x1D,0x25,0x04,0x21,0x30,0x1F,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,
0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x09,0x60,
0x86,0x48,0x01,0x86,0xF8,0x42,0x04,0x01,0x30,0x36,0x06,0x03,0x55,0x1D,0x1F,0x04,
0x2F,0x30,0x2D,0x30,0x2B,0xA0,0x29,0xA0,0x27,0x86,0x25,0x68,0x74,0x74,0x70,0x3A,
0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x74,0x68,0x61,0x77,0x74,0x65,0x2E,0x63,0x6F,0x6D,
0x2F,0x54,0x68,0x61,0x77,0x74,0x65,0x53,0x47,0x43,0x43,0x41,0x2E,0x63,0x72,0x6C,
0x30,0x72,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x66,0x30,0x64,
0x30,0x22,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x16,0x68,0x74,
0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x74,0x68,0x61,0x77,0x74,0x65,
0x2E,0x63,0x6F,0x6D,0x30,0x3E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,
0x86,0x32,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x68,0x61,
0x77,0x74,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,
0x72,0x79,0x2F,0x54,0x68,0x61,0x77,0x74,0x65,0x5F,0x53,0x47,0x43,0x5F,0x43,0x41,
0x2E,0x63,0x72,0x74,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,
0x30,0x00,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,
0x00,0x03,0x81,0x81,0x00,0x57,0x4B,0xBC,0xA4,0x43,0xE7,0xE0,0x01,0x92,0xA0,0x96,
0x35,0xF9,0x18,0x08,0x88,0x1D,0x7B,0x70,0x19,0x8F,0xF9,0x36,0xB2,0x05,0x3A,0x05,
0xCA,0x14,0x59,0x4D,0x24,0x0E,0xE5,0x8A,0xAF,0x4E,0x87,0x5A,0xF7,0x1C,0x2A,0x96,
0x8F,0xCB,0x61,0x40,0x9E,0xD2,0xB4,0x38,0x40,0x21,0x24,0xC1,0x4F,0x1F,0xCB,0x13,
0x4A,0x8F,0x95,0x02,0xDF,0x91,0x3D,0xD6,0x40,0xEB,0x11,0x6F,0x9B,0x10,0xA1,0x6F,
0xCE,0x91,0x5E,0x30,0xF6,0x6D,0x13,0x5E,0x15,0xA4,0x2E,0xC2,0x18,0x9E,0x00,0xC3,
0xD8,0x32,0x67,0x47,0xFC,0xB8,0x1E,0x9A,0xD9,0x9A,0x8E,0xCC,0xFF,0x7C,0x12,0xB7,
0x03,0xBF,0x52,0x20,0xCF,0x21,0xF4,0xF3,0x77,0xDD,0x12,0x15,0xF0,0x94,0xFA,0x90,
0xD5,0xE3,0x59,0x68,0x81
};

// The certificate for the thawte CA that issued the above
unsigned char thawtecert[] = {
0x30,0x82,0x03,0x23,0x30,0x82,0x02,0x8C,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x30,
0x00,0x00,0x02,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,
0x05,0x00,0x30,0x5F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,
0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x37,0x30,0x35,0x06,0x03,
0x55,0x04,0x0B,0x13,0x2E,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,
0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,
0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,
0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x35,0x31,0x33,0x30,0x30,0x30,
0x30,0x30,0x30,0x5A,0x17,0x0D,0x31,0x34,0x30,0x35,0x31,0x32,0x32,0x33,0x35,0x39,
0x35,0x39,0x5A,0x30,0x4C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
0x5A,0x41,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x54,0x68,0x61,
0x77,0x74,0x65,0x20,0x43,0x6F,0x6E,0x73,0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x28,
0x50,0x74,0x79,0x29,0x20,0x4C,0x74,0x64,0x2E,0x31,0x16,0x30,0x14,0x06,0x03,0x55,
0x04,0x03,0x13,0x0D,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x53,0x47,0x43,0x20,0x43,
0x41,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xD4,0xD3,
0x67,0xD0,0x8D,0x15,0x7F,0xAE,0xCD,0x31,0xFE,0x7D,0x1D,0x91,0xA1,0x3F,0x0B,0x71,
0x3C,0xAC,0xCC,0xC8,0x64,0xFB,0x63,0xFC,0x32,0x4B,0x07,0x94,0xBD,0x6F,0x80,0xBA,
0x2F,0xE1,0x04,0x93,0xC0,0x33,0xFC,0x09,0x33,0x23,0xE9,0x0B,0x74,0x2B,0x71,0xC4,
0x03,0xC6,0xD2,0xCD,0xE2,0x2F,0xF5,0x09,0x63,0xCD,0xFF,0x48,0xA5,0x00,0xBF,0xE0,
0xE7,0xF3,0x88,0xB7,0x2D,0x32,0xDE,0x98,0x36,0xE6,0x0A,0xAD,0x00,0x7B,0xC4,0x64,
0x4A,0x3B,0x84,0x75,0x03,0xF2,0x70,0x92,0x7D,0x0E,0x62,0xF5,0x21,0xAB,0x69,0x36,
0x84,0x31,0x75,0x90,0xF8,0xBF,0xC7,0x6C,0x88,0x1B,0x06,0x95,0x7C,0xC9,0xE5,0xA8,
0xDE,0x75,0xA1,0x2C,0x7A,0x68,0xDF,0xD5,0xCA,0x1C,0x87,0x58,0x60,0x19,0x02,0x03,
0x01,0x00,0x01,0xA3,0x81,0xFE,0x30,0x81,0xFB,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,
0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x0B,0x06,
0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x11,0x06,0x09,0x60,0x86,
0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x28,0x06,
0x03,0x55,0x1D,0x11,0x04,0x21,0x30,0x1F,0xA4,0x1D,0x30,0x1B,0x31,0x19,0x30,0x17,
0x06,0x03,0x55,0x04,0x03,0x13,0x10,0x50,0x72,0x69,0x76,0x61,0x74,0x65,0x4C,0x61,
0x62,0x65,0x6C,0x33,0x2D,0x31,0x35,0x30,0x31,0x06,0x03,0x55,0x1D,0x1F,0x04,0x2A,
0x30,0x28,0x30,0x26,0xA0,0x24,0xA0,0x22,0x86,0x20,0x68,0x74,0x74,0x70,0x3A,0x2F,
0x2F,0x63,0x72,0x6C,0x2E,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,
0x6D,0x2F,0x70,0x63,0x61,0x33,0x2E,0x63,0x72,0x6C,0x30,0x32,0x06,0x08,0x2B,0x06,
0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x26,0x30,0x24,0x30,0x22,0x06,0x08,0x2B,0x06,
0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x16,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,
0x63,0x73,0x70,0x2E,0x74,0x68,0x61,0x77,0x74,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x34,
0x06,0x03,0x55,0x1D,0x25,0x04,0x2D,0x30,0x2B,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,
0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x09,0x60,
0x86,0x48,0x01,0x86,0xF8,0x42,0x04,0x01,0x06,0x0A,0x60,0x86,0x48,0x01,0x86,0xF8,
0x45,0x01,0x08,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x55,0xAC,0x63,0xEA,0xDE,0xA1,0xDD,0xD2,0x90,
0x5F,0x9F,0x0B,0xCE,0x76,0xBE,0x13,0x51,0x8F,0x93,0xD9,0x05,0x2B,0xC8,0x1B,0x77,
0x4B,0xAD,0x69,0x50,0xA1,0xEE,0xDE,0xDC,0xFD,0xDB,0x07,0xE9,0xE8,0x39,0x94,0xDC,
0xAB,0x72,0x79,0x2F,0x06,0xBF,0xAB,0x81,0x70,0xC4,0xA8,0xED,0xEA,0x53,0x34,0xED,
0xEF,0x1E,0x53,0xD9,0x06,0xC7,0x56,0x2B,0xD1,0x5C,0xF4,0xD1,0x8A,0x8E,0xB4,0x2B,
0xB1,0x37,0x90,0x48,0x08,0x42,0x25,0xC5,0x3E,0x8A,0xCB,0x7F,0xEB,0x6F,0x04,0xD1,
0x6D,0xC5,0x74,0xA2,0xF7,0xA2,0x7C,0x7B,0x60,0x3C,0x77,0xCD,0x0E,0xCE,0x48,0x02,
0x7F,0x01,0x2F,0xB6,0x9B,0x37,0xE0,0x2A,0x2A,0x36,0xDC,0xD5,0x85,0xD6,0xAC,0xE5,
0x3F,0x54,0x6F,0x96,0x1E,0x05,0xAF
};

int main(int argc, char **argv)
{
       // an easy program to verify the signature on one certificate using the
       // public key from another. This is really just a test for GetPublicKeyFromCert()!
       // you need to do a great deal more verification before deciding to trust a
       // certificate in most applications.
       ByteQueue googleq, thawteq, googletbs, thawtespki;
       SecByteBlock certSignature;
       googleq.Put(googlecert,sizeof(googlecert));
       thawteq.Put(thawtecert,sizeof(thawtecert));
       try {
               GetPublicKeyFromCert(thawteq,thawtespki);
       }catch(std::exception &){
               cerr << "Failed to extract the public key from the CA certificate." << endl;
               return 1;
       }
       cout << "Public key read from Thawte CA certificate." << endl;

       OID sigAlgOID;

       try {
               // first, extract the data that the signature covers
               BERSequenceDecoder x509Cert(googleq);
               BERSequenceDecoder tbsCert(x509Cert);
               DERSequenceEncoder tbsEnc(googletbs);
               tbsCert.TransferAllTo(tbsEnc);
               tbsEnc.MessageEnd();
               // find the algorithm used to sign the data
               BERSequenceDecoder sigAlg(x509Cert);
               sigAlgOID.BERDecode(sigAlg);
               sigAlg.SkipAll();
               // extract the actual signature
               unsigned int unused = 0;
               BERDecodeBitString(x509Cert,certSignature,unused);
               cout << "Signature decoded. " << unused << " bits unused in the encoding." << endl;
               x509Cert.SkipAll();
       }catch(std::exception &){
               cerr << "Error decoding the Google server certificate for signature verification." << endl;
               return 1;
       }
       PK_VerifierPtr verifier;
       if(sigAlgOID == md5withRSAEncryption()) {
               verifier = PK_VerifierPtr(new RSASS<PKCS1v15,CryptoPP::MD5>::Verifier(thawtespki));
               cout << "Signature algorithm is RSA with MD5 hash." << endl;
       } else if(sigAlgOID == sha1withRSAEncryption()) {
               verifier = PK_VerifierPtr(new RSASS<PKCS1v15,CryptoPP::SHA1>::Verifier(thawtespki));
               cout << "Signature algorithm is RSA with SHA1 hash." << endl;
       } else {
               cerr << "This test program does not support the algorithm used for signing." << endl;
               return 1;
       }

       if(certSignature.size() != verifier->SignatureLength()) {
               cerr << "The signature size is does not match the algorithm used for signing." << endl;
               return 1;
       }
       CryptoPP::SignatureVerificationFilter vf(*verifier);
       try {
               vf.Put(certSignature,certSignature.size());
               googletbs.TransferAllTo(vf);
               vf.MessageEnd();
       }catch(std::exception &e){
               cerr << "Caught an exception while verifying the signature:" << endl;
               cerr << "\t" << e.what() << endl;
               return 1;
       }
       if(vf.GetLastResult()) {
               cout << "The signature verified." << endl;
       } else {
               cout << "Signature verification failed." << endl;
       }
       return 0;
}