locked
How to read certificates and public keys from smart cards with Crypto API in Windows XP? RRS feed

  • Question

  •    Hello.

       I want to read certificates (at least) and stand alone public keys (at best) from any smart cards containers (at best) in Windows XP with Miscrosoft Crypto API.
    My languege - C++ (dll library).
       Smart cards: for example Axalto, Schlumberger.
       I have managed to read signers certificate from my test smart cards.
    Like that (I found sample in the internet) (my code is shortened):

    // enum containers:
    CryptGetProvParam(smartCryptoProvider, PP_ENUMCONTAINERS, containerBuf,
       &containerBufLen, isFirstFlag));
    ...
    // read container:

    CryptAcquireContext(&hCryptProv, (LPCSTR)containerBuf,
       smartCryptoProviderName, PROV_RSA_FULL, 0));
    ...
    // read AT_KEYEXCHANGE (or KP_CERTIFICATE):
    HCRYPTKEY exchange_key = NULL;
    CryptGetUserKey(hCryptProv, AT_KEYEXCHANGE, &exchange_key);

       There are two containers in my card and I can see, that the second container
    holds CA certificate. I can't read CA certificate by my method because it doesn't have public or private key with it in container (signers certificate do have public and private keys in the same container).

       I need CA certificate to verify signers certificate and can anybody, please, help me to read it from smart card?

       The other way - to load Axalto PKCS#11 librarry. But I'd like to work with any other cards too.

       The third way - to use low level APDU commands?
    But they are much more difficult to use than CryptoAPI.

        May be there is still some way to read CA (or even stand along CA public key) from smart card with only pure Crypto API in Windows XP?

        Thank you very much in advance!

        Timur.
     
    Sunday, December 25, 2011 7:30 AM

All replies

  • PKCS#11 is a standard widely supported by hardware vendors, so for your particular task it's a good idea to use that interface instead of CryptoAPI. PKCS#11 lets you access certificates an public keys independently (and private keys as well, but you don't need them).
    Sincerely yours, Eugene Mayevski
    Sunday, December 25, 2011 1:02 PM
  • Check the certificates you do have for Authority Information Access

    http://tools.ietf.org/html/rfc5280#section-4.2.2.1

     

    Sunday, December 25, 2011 10:01 PM
  • Thank you for your advice.
    May be I will look at that section sometime.

         Timur.

     

    Friday, January 6, 2012 6:39 PM
  •    Thank you for your advice.
    I know that getting PKCS#11 library from smart cart vendor would be the more convenient way.

       But firstly I am trying to read that files with APDU commands.
    I found "Cryptoflex Cards Programmer's Guide" (June 2002) and tried the following code:

     

    extern "C" int WINAPI SmartCardDump(BYTE *dumpBuf,
      DWORD *dumpBufLen) {
    	SCARDCONTEXT hSC;
            int res;
    
    	if ((res = SCardEstablishContext(SCARD_SCOPE_USER,
               NULL, NULL, &hSC)) != SCARD_S_SUCCESS) {
    	   goto FINALLY1;
    	   }
    
            SCARDHANDLE hCardHandle;
            DWORD dwAP = smartReaderProtocol;
    
            if ((res = SCardConnect(hSC, smartReaderName,
               SCARD_SHARE_SHARED, smartReaderProtocol,
               &hCardHandle, &dwAP)) != SCARD_S_SUCCESS) {
               goto FINALLY2;
    	   }
    
    	// send PIN
    	BYTE APDU_C0[] = {
              0xC0, // CLA
    	  0x20, // INS
    	  0x00, // P1
    	  0x01, // P2
    	  0x08, // Lc
    	  48, // PIN = '00000000'
    	  48,
    	  48,
    	  48,
              48,
    	  48,
    	  48,
    	  48
    	  };
    	BYTE APDU_R0[258];
            DWORD NumberOfBytesReceived0 = sizeof(APDU_R0);
    
            res |= SCardTransmit(hCardHandle,
    	  SCARD_PCI_T0,
    	  APDU_C0,
    	  sizeof(APDU_C0),
    	  NULL,
    	  APDU_R0,
    	  &NumberOfBytesReceived0);
    
    	// select card's Master File
    	BYTE APDU_C[] = {
    	  0xC0, // CLA
    	  0xA4, // INS
              0x00, // P1
    	  0x00, // P2
    	  0x02, // Lc - Length of command data that follows
    	  0x3F,
    	  0x00
              };
            BYTE APDU_R[258];
    	DWORD NumberOfBytesReceived = sizeof(APDU_R);
    
            res |= SCardTransmit(hCardHandle,
    	  SCARD_PCI_T0,
    	  APDU_C,
    	  sizeof(APDU_C),
    	  NULL,
    	  APDU_R,
    	  &NumberOfBytesReceived);
    
    	// get response on select file
            BYTE APDU_C2[] = {
    	  0xC0, // CLA
    	  0xC0, // INS
              0x00, // P1
    	  0x00, // P2
    	  20  // Le - I get 20 bytes - I checked that previously
              };
            BYTE APDU_R2[258];
    	DWORD NumberOfBytesReceived2 = 22;
    
            res |= SCardTransmit(hCardHandle,
    	  SCARD_PCI_T0,
    	  APDU_C2,
    	  sizeof(APDU_C2),
    	  NULL,
    	  APDU_R2,
    	  &NumberOfBytesReceived2);
    
    	// DIR NEXT - to get the first file under Master File
            BYTE APDU_C4[] = {
    	  0xF0, // CLA - the instruction class
    	  0xA8, // INS - the instruction code
              0x00, // P1
    	  0x00, // P2
    	  0x04  // Le receive first 4 bytes about file
              };
            BYTE APDU_R4[258];
    	DWORD NumberOfBytesReceived4 = 6;
    
            res |= SCardTransmit(hCardHandle,
    	  SCARD_PCI_T0,
    	  APDU_C4,
    	  sizeof(APDU_C4),
    	  NULL,
    	  APDU_R4,
    	  &NumberOfBytesReceived4);
    
    	// copy result out of the function - I'll save it in dump file
    	memcpy_s(dumpBuf, NumberOfBytesReceived4,
              &APDU_R4[0], NumberOfBytesReceived4);
    	*dumpBufLen = NumberOfBytesReceived4;
    
    	res |= SCardDisconnect(hCardHandle,
              SCARD_LEAVE_CARD);
    	   
    FINALLY2:
            res |= SCardReleaseContext(hSC);
    
    FINALLY1:
    	return res;
    }
    
    

     


       But DIR NEXT command returns me the code 0x69 0x82 - "The required AC was not satisfied"
    Although I checked the response from the VERIFY CHV command (PIN-код) - It was 0x90 0x00 - "The command succeeded: The user’s access rights are established."

       I can't understand now - no way to select and read public files from smart card with low level APDU commands? It is unlikely. More likely that I made a mistake or I am not understanding something about selecting files from smart card with APDU commands.

           Timur.


     


    • Edited by Timur89K Friday, January 6, 2012 7:04 PM
    Friday, January 6, 2012 7:03 PM
  • You might try your pin verify AFTER the Select MF.
    Monday, January 9, 2012 4:18 PM
  •    Thank you for your suggestion! 

       I tryed this variant with the same result.
    I even try to send PIN twice: before and after Select MF: same result.

       After that I found from Cryptoflex Programmer Guide that Next DIR command for MF demands Security Officer authorization. So, it is not for ordinary user.

       Now I am trying to get that public key and certificate with PKCS#11.
    My PKCS#11 dll is slbck.dll
    I found from Cryptoflex Developer Guide that I need to use PKCS#11 version 2.01.
    I download documentation and *.h files from this site:

    http://www.cryptsoft.com/pkcs11doc

       When I'll finish with this task I will place here my solution.

       Timur.

    Sunday, January 15, 2012 2:37 PM
  • Hello.

    I have managed to read CA certificate from smart card:

     

    PCCERT_CONTEXT ReadCardCACert(DWORD *errorCode, DWORD *resultCode, DWORD *PKCS11Code) {
      PCCERT_CONTEXT pCACert = NULL;
    
      // check my PKCS11 library (loaded another place)
      if (smartPKCS11ModulePath == NULL) {
        *resultCode = SMART_PKCS11_LIB_NOT_LOADED;
        goto FINALLY1;
        }
    
        // no errors yet
        *errorCode = 0;
        *resultCode = 0;
        *PKCS11Code = 0;
    
        // find first slot with token
        CK_RV rv;
        CK_SLOT_ID slotID;
        CK_SLOT_ID SlotList[100];
        CK_ULONG ulCount = sizeof(SlotList) / sizeof(CK_SLOT_ID);
        CK_SESSION_HANDLE hSession;
       
        rv = (*ckPKCS11FuncPtr->C_GetSlotList)(
         TRUE, SlotList, &ulCount);
        if (rv != CKR_OK) {
           *resultCode = SMART_PKCS11_ERROR;
           *PKCS11Code = rv;
           goto FINALLY1;
           }
    
       // no active slot?
       if (ulCount <= 0) {
          *resultCode = SMART_PKCS11_NO_ACTIVE_TOKEN;
          goto FINALLY1;
          }
    
        // take first slot
        slotID = SlotList[0];
    
        // open read-only session
        rv = (*ckPKCS11FuncPtr->C_OpenSession)(slotID,
          CKF_SERIAL_SESSION, 0, 0, &hSession);
        if (rv != CKR_OK) {
           *resultCode = SMART_PKCS11_ERROR;
           *PKCS11Code = rv;
           goto FINALLY1;
           }
    
        // find card certificates
        CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
        CK_BYTE token_object = TRUE;
        CK_ATTRIBUTE find_template[] = {
    	{CKA_CLASS, &certClass, sizeof(certClass)},
    	{CKA_TOKEN, &token_object, sizeof(token_object)}
        };
        CK_ULONG objectCount;
        CK_OBJECT_HANDLE hObject;
    
        rv = (*ckPKCS11FuncPtr->C_FindObjectsInit)(
          hSession, find_template, 2);
        if (rv != CKR_OK) {
          *resultCode = SMART_PKCS11_ERROR;
          *PKCS11Code = rv;
          goto FINALLY2;
          }
    
        // lengths template
        CK_ATTRIBUTE get_lens_template[] = {
          {CKA_SUBJECT, NULL_PTR, 0},
          {CKA_ISSUER, NULL_PTR, 0},
          {CKA_VALUE, NULL_PTR, 0}
        };
    
        CK_LONG subject_len = 0;
        CK_LONG issuer_len = 0;
        CK_LONG value_len = 0;
    
        CK_ATTRIBUTE subject_issuer_template[] = {
          {CKA_SUBJECT, NULL_PTR, 0},
          {CKA_ISSUER, NULL_PTR, 0}
        };
    
        bool CA_is_found = false;
        for (int i = 0; i < 100; i++) {
    	 rv = (*ckPKCS11FuncPtr->C_FindObjects)(hSession,
               &hObject, 1, &objectCount);
             if (rv != CKR_OK) {
    	    *resultCode = SMART_PKCS11_ERROR;
    	    *PKCS11Code = rv;
    	    break;
    	    }
    
    	 // no CA certifiacte on the card
             if (objectCount == 0) {
    	    *resultCode = SMART_PKCS11_NO_CARD_CA_CERT;
    	    break;
    	    }
    
            // find lengths
    	subject_len = 0;
    	issuer_len = 0;
    	value_len = 0;
    
        	get_lens_template[0].pValue = NULL_PTR;
            get_lens_template[0].ulValueLen = 0;
            get_lens_template[1].pValue = NULL_PTR;
            get_lens_template[1].ulValueLen = 0;
    	get_lens_template[2].pValue = NULL_PTR;
            get_lens_template[2].ulValueLen = 0;
    
            rv = (*ckPKCS11FuncPtr->C_GetAttributeValue)(hSession,
              hObject, &get_lens_template[0], 3);
            if (rv != CKR_OK) {
    	   *resultCode = SMART_PKCS11_ERROR;
    	   *PKCS11Code = rv;
    	   break;
    	   }
    
    	subject_len = (CK_LONG)get_lens_template[0].ulValueLen;
    	issuer_len = (CK_LONG)get_lens_template[1].ulValueLen;
    	value_len = (CK_LONG)get_lens_template[2].ulValueLen;
    
    	if ((subject_len == -1) || (issuer_len == -1)
               || (value_len == -1) || (subject_len == 0)
               || (issuer_len == 0) || (value_len == 0)) continue;
    
            // CA: ISSUER = SUBJECT
            if (subject_len != issuer_len) continue;
    
    	CK_BYTE_PTR pSubject = new BYTE[subject_len];
    	CK_BYTE_PTR pIssuer = new BYTE[issuer_len];
    
    	subject_issuer_template[0].pValue = pSubject;
    	subject_issuer_template[0].ulValueLen = subject_len;
            subject_issuer_template[1].pValue = pIssuer;
    	subject_issuer_template[1].ulValueLen = issuer_len;
    
            rv = (*ckPKCS11FuncPtr->C_GetAttributeValue)(hSession,
              hObject, &subject_issuer_template[0], 2);
            if (rv != CKR_OK) {
    	   *resultCode = SMART_PKCS11_ERROR;
    	   *PKCS11Code = rv;
    
    	   if (pSubject != NULL_PTR) delete[] pSubject;
    	   if (pIssuer != NULL_PTR) delete[] pIssuer;
    
    	   break;
               }
    
            // CA: ISSUER = SUBJECT
    	if (memcmp(pSubject, pIssuer, subject_len) == 0) {
    	   if (pSubject != NULL_PTR) delete[] pSubject;
    	   if (pIssuer != NULL_PTR) delete[] pIssuer;
    
    	   // it is CA
    	   CA_is_found = true;
    	   break;
    	   }
    
               if (pSubject != NULL_PTR) delete[] pSubject;
               if (pIssuer != NULL_PTR) delete[] pIssuer;
    	   }
    
        rv = (*ckPKCS11FuncPtr->C_FindObjectsFinal)(hSession);
        if (rv != CKR_OK) {
           *resultCode = SMART_PKCS11_ERROR;
           *PKCS11Code = rv;
           goto FINALLY2;
           }
    
        // if error - no continue
        if (*resultCode != 0) goto FINALLY2;
    
        // load VALUE of the CA
        CK_BYTE_PTR pValue = new BYTE[value_len];
    
        CK_ATTRIBUTE get_value_template[] = {
          {CKA_VALUE, NULL_PTR, 0}
        };
        get_value_template[0].pValue = pValue;
        get_value_template[0].ulValueLen = value_len;
    
        rv = (*ckPKCS11FuncPtr->C_GetAttributeValue)(hSession,
          hObject, &get_value_template[0], 1);
        if (rv != CKR_OK) {
          *resultCode = SMART_PKCS11_ERROR;
          *PKCS11Code = rv;
          } else {
          // load CA
         pCACert = CertCreateCertificateContext(
           X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
           pValue, value_len);
         if (pCACert == NULL) *errorCode = GetLastError();       
         }
    
       if (pValue != NULL_PTR) delete[] pValue;
    
    FINALLY2:
       rv = (*ckPKCS11FuncPtr->C_CloseSession)(hSession);
       if (rv != CKR_OK) {
         *resultCode = SMART_PKCS11_ERROR;
         *PKCS11Code = rv;
         }
    
    FINALLY1:
        return pCACert;
    }
    
    

     

       But now, I have problems with the second task: convert CA public key into normal CERT_PUBLIC_KEY_INFO form.

    Suppose I have managed to find and get CA public key's:
    CKA_MODULUS, CKA_MODULUS_BITS and CKA_PUBLIC_EXPONENT attributes,
    but now I beleve I have a problem with putting them together into Public Key Blob.

    I suppose there are some difficulties with big or little endian encodings.

    My code for now to build Public Key Blob:

     

      /*
      ... till here I have BYTE* pCKA_PUBLIC_EXPONENT, 
      pCKA_MODULUS and pCKA_MODULUS_BITS 
      */
    
      // construct Public Key Blob
      BLOBHEADER blobheader;
      RSAPUBKEY rsapubkey;
    
      blobheader.bType = PUBLICKEYBLOB; // 0x06
      blobheader.bVersion = CUR_BLOB_VERSION; // 0x02
      blobheader.reserved = 0; // 0x0000
      blobheader.aiKeyAlg = CALG_RSA_KEYX; // 0x0000A400
      rsapubkey.magic     = 0x31415352; // "RSA1"
      rsapubkey.bitlen = 1024; // 0x00000400 - RSA1024 - I know
      // I not very experienced C++ programmer (sorry):
      rsapubkey.pubexp =  (DWORD)pCKA_PUBLIC_EXPONENT[3]
        + (((DWORD)pCKA_PUBLIC_EXPONENT[2]) << 8)
        + (((DWORD)pCKA_PUBLIC_EXPONENT[1]) << 16)
        + (((DWORD)pCKA_PUBLIC_EXPONENT[0]) << 24);
    
    
      BYTE *PubKeyBLOB = new BYTE[(sizeof(blobheader)
        + sizeof(rsapubkey) + modulus_len)];
      memcpy_s(PubKeyBLOB, sizeof(blobheader),
        &blobheader, sizeof(blobheader));
      memcpy_s((PubKeyBLOB + sizeof(blobheader)),
        sizeof(rsapubkey), &rsapubkey, sizeof(rsapubkey));
      memcpy_s((PubKeyBLOB + sizeof(blobheader)
        + sizeof(rsapubkey)), modulus_len,
        pCKA_MODULUS, modulus_len);
    
      // encode to RSA_CSP_PUBLICKEYBLOB
      BYTE *CryptBlob = NULL;
      DWORD CryptBlobLen = 0;
    
      if (!CryptEncodeObject(
         PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
         RSA_CSP_PUBLICKEYBLOB, PubKeyBLOB,
         NULL, &CryptBlobLen)) {
         res = GetLastError();
         goto FINALLY5; // goto errors
         }
    
      CryptBlob = new BYTE[CryptBlobLen];
    
      if (!CryptEncodeObject(
        PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
        RSA_CSP_PUBLICKEYBLOB, PubKeyBLOB,
        CryptBlob, &CryptBlobLen)) {
        res = GetLastError();
        goto FINALLY6; // goto errors
        }
    
       // fill CERT_PUBLIC_KEY_INFO structure
       CERT_PUBLIC_KEY_INFO CAPublicKey;
       CAPublicKey.Algorithm.pszObjId = szOID_RSA_RSA;
       CAPublicKey.Algorithm.Parameters.cbData = 2;
       CAPublicKey.Algorithm.Parameters.pbData =
         (BYTE *) "\005"; // don't realy no why (was in internet sample)
       CAPublicKey.PublicKey.cbData = CryptBlobLen;
       CAPublicKey.PublicKey.pbData = CryptBlob;
       CAPublicKey.PublicKey.cUnusedBits = 0;
    
       ...
    
       // I get here my User certificate from card
       PCCERT_CONTEXT pCertContext = ReadCertFromCard(...);
    
       // and try to check it with CA public key
       if (pCertContext != NULL) {
         if (!CryptVerifyCertificateSignatureEx(smartCryptoProvider,
    	X509_ASN_ENCODING,
    	CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
            (void *)(pCertContext),
    	CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY,
            (void *)(&CAPublicKey), 0, NULL)) {
    	res = GetLastError();
            // and get Error N8 "Not enough storage is available
            // to process the command"
            // or Error N2148073478 "Invalid Signature"
            }
    
         CertFreeCertificateContext(pCertContext);
         }
    
    


    If anybody did construct public key blobs this way,
    please help to understand how!

     

         Timur.

     

     

    Saturday, January 21, 2012 7:03 PM
  • If you have a PCCERT_CONTEXT, then the easy way to get a PUBLICKEYBLOB is to build a public key 

    then use ::CryptExportKey with PUBLICKEYBLOB.

     

     

    void getBlobFromCertificate( Cspprov & prov, PCCERT_CONTEXT certcon )

    {

    PCERT_PUBLIC_KEY_INFO pNewPubKeyinfo;

    pNewPubKeyinfo = &(certcon->pCertInfo->SubjectPublicKeyInfo);

     

    HCRYPTKEY m_hKey;

    ::CryptImportPublicKeyInfo( prov.getHCryptProv(), X509_ASN_ENCODING,  pNewPubKeyinfo, &m_hKey )

    // then use ::CryptExportKey with PUBLICKEYBLOB.

    }

     

    Saturday, January 21, 2012 7:36 PM
  •    But in this situation I have PCCERT_CONTEXT of the User certificate from smart card.

       And on a smart card there is no CA certificate, only CA Public Key.

    With the help of PKCS#11 library I obtain CA Pablic Key
    CKA_MODULUS, CKA_MODULUS_BITS and CKA_PUBLIC_EXPONENT attributes.

    And now I need to costruct from these attributes CERT_PUBLIC_KEY_INFO to use it in CryptVerifyCertificateSignatureEx to verify User certificate with CA Public Key.

    And it is the problem: first I need to construct Public Key Blob:
    BLOBHEADER
    RSAPUBKEY
    Modulus (of the CA Public Key)

    I suspect that I made mistake(s) in constructing Public Key Blob:

    /*
    ... till here I have BYTE* pCKA_PUBLIC_EXPONENT,
    pCKA_MODULUS and pCKA_MODULUS_BITS
    */


    // construct Public Key Blob
    BLOBHEADER blobheader;
    RSAPUBKEY rsapubkey;

    blobheader.bType = PUBLICKEYBLOB; // 0x06
    blobheader.bVersion = CUR_BLOB_VERSION; // 0x02
    blobheader.reserved = 0; // 0x0000
    blobheader.aiKeyAlg = CALG_RSA_KEYX; // 0x0000A400
    rsapubkey.magic = 0x31415352; // "RSA1"
    rsapubkey.bitlen = 1024; // 0x00000400 - RSA1024 - I know for sure
    // I am not very experienced C++ programmer (sorry):
    rsapubkey.pubexp = (DWORD)pCKA_PUBLIC_EXPONENT[3]
    + (((DWORD)pCKA_PUBLIC_EXPONENT[2]) << 8)
    + (((DWORD)pCKA_PUBLIC_EXPONENT[1]) << 16)
    + (((DWORD)pCKA_PUBLIC_EXPONENT[0]) << 24);


    BYTE *PubKeyBLOB = new BYTE[(sizeof(blobheader)
    + sizeof(rsapubkey) + modulus_len)];
    memcpy_s(PubKeyBLOB, sizeof(blobheader),
    &blobheader, sizeof(blobheader));
    memcpy_s((PubKeyBLOB + sizeof(blobheader)),
    sizeof(rsapubkey), &rsapubkey, sizeof(rsapubkey));
    memcpy_s((PubKeyBLOB + sizeof(blobheader)
    + sizeof(rsapubkey)), modulus_len,
    pCKA_MODULUS, modulus_len);
    Sunday, January 22, 2012 6:22 AM
  • I took a 2048 bit certificate and generated its PUBLICKEYBLOB and its  CERT_PUBLIC_KEY_INFO for comparison.
    You can see that the PUBLICKEYBLOB has its modulus in little endian.  A very frequent error is to stick a big endian modulus where PUBLICKEYBLOB wants a little endian.  I checked the PKCS11 documentation and they define

    Big integer: a string of CK_BYTEs representing an unsigned integer of arbitrary size, most-significant byte first (e.g., the integer 32768 is represented as the 2-byte string 0x80 0x00)

    Table 35, RSA Public Key Object Attributes

    Attribute

    Data type

    Meaning

    CKA_MODULUS<sup>1,4</sup>

    Big integer

    Modulus n

    CKA_MODULUS_BITS<sup>2,3</sup>

    CK_ULONG

    Length in bits of modulus n

    CKA_PUBLIC_EXPONENT<sup>1</sup>

    Big integer

    Public exponent e

    <sup>- </sup>

     
      So unless you have reversed the byte order of your modulus, you will have trouble.  (Exponent too) Hope this helps to compare against your data.
     
    PUBLICKEYBLOB
    
    06  02    00 00     00 a4 00 00   52 53 41 31   00 08 00 00
    
    01 00 01 00
    
    6b e1 bd 2d fc 7d d8 85 e6 ac 9d 65 db d4 03 2d
    61 ac 34 98 29 d2 7b 5f fc 5e 5a 59 a8 00 fa 2f
    bf 1c 0c b8 ba be 12 8f cc 08 8e c1 da 59 2c e4
    48 ee e9 f8 7d 97 ab 50 1a 0c e3 c6 06 aa ea e8
    07 a9 a3 c9 5c 54 45 7f a3 e8 e5 3c f7 57 6c 26
    b7 a4 50 b9 18 e7 40 ff d7 57 3e 4c 6d 53 dc 75
    31 e9 93 2c c2 dd 34 10 2b d9 7a f3 b7 66 92 fa
    d7 70 4c 80 6b 68 ac e0 96 0a 7c 87 65 af 1b cd
    7b 6e c3 41 9b 26 26 74 78 53 d5 4e 34 4e ad bd
    f2 da e5 1a d7 29 3c b9 a1 4d 09 8b 53 ad 8f 0f
    5f 8b b1 64 50 33 a6 0c 2b 07 fe d7 82 f8 70 ba
    7b 58 8d 42 5c 03 7e d4 9d 57 95 5f 10 da 4e 58
    5c e0 6f be 2a 35 43 c6 cb 5b 98 7a 4c 96 7a c3
    b9 e0 0e 22 75 6e d0 fa 8a fe 09 87 83 8f ff 46
    f8 2b 91 3f 1b c2 c5 c4 27 a4 91 9c e3 2a 58 11
    d9 bf 5c 1b ed 57 34 32 17 d1 76 22 e0 e3 be 97 
     
     
    CERT_PUBLIC_KEY_INFO
    Algorithm 1.2.840.113549.1.1.1     szOID_RSA_RSA
    Algorithm Parameters 05 00
    PublicKey
    30 82 01 0a          universal Sequence of len 10a
    02 82 01 01          universal Integer of len 101
    00
    97 be e3 e0 22 76 d1 17 32 34 57 ed 1b 5c bf d9                Note big endian now.
    11 58 2a e3 9c 91 a4 27 c4 c5 c2 1b 3f 91 2b f8
    46 ff 8f 83 87 09 fe 8a fa d0 6e 75 22 0e e0 b9
    c3 7a 96 4c 7a 98 5b cb c6 43 35 2a be 6f e0 5c
    58 4e da 10 5f 95 57 9d d4 7e 03 5c 42 8d 58 7b
    ba 70 f8 82 d7 fe 07 2b 0c a6 33 50 64 b1 8b 5f
    0f 8f ad 53 8b 09 4d a1 b9 3c 29 d7 1a e5 da f2
    bd ad 4e 34 4e d5 53 78 74 26 26 9b 41 c3 6e 7b
    cd 1b af 65 87 7c 0a 96 e0 ac 68 6b 80 4c 70 d7
    fa 92 66 b7 f3 7a d9 2b 10 34 dd c2 2c 93 e9 31
    75 dc 53 6d 4c 3e 57 d7 ff 40 e7 18 b9 50 a4 b7
    26 6c 57 f7 3c e5 e8 a3 7f 45 54 5c c9 a3 a9 07
    e8 ea aa 06 c6 e3 0c 1a 50 ab 97 7d f8 e9 ee 48
    e4 2c 59 da c1 8e 08 cc 8f 12 be ba b8 0c 1c bf
    2f fa 00 a8 59 5a 5e fc 5f 7b d2 29 98 34 ac 61
    2d 03 d4 db 65 9d ac e6 85 d8 7d fc 2d bd e1 6b
    02 03 01 00 01     Exponent
     

    • Edited by Andrew7Webb Sunday, January 22, 2012 3:18 PM
    Sunday, January 22, 2012 3:03 PM