X.509 Example
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; }