Search code examples
c++certificatefirefox-addonmozilla

Parse addon id from mozilla.rsa file


I am trying to read mozilla.rsa file and parse the addon Id using C++.

My effort:

std::string rsaPath = xpiDir + "\\META-INF\\mozilla.rsa";

int rets = system(("CertUtil " + rsaPath + " | findstr " + "S=CA").c_str());

//
.....
My additional logic.............
.....
///

It's working fine on Windows 7 and later versions. But, there is no on Windows xp.

CertUtil

Is there any way to read addon id from mozilla.rsa file using C or C++?


Solution

  • Indeed, the file can be read and parsed with Windows CryptoAPI.

    The file mozilla.rsa of Mozilla extension is a PKCS#7 signature. On Linux it can be viewed with the following command:

    openssl pkcs7 -print -inform der -in META-INF/mozilla.rsa.

    The signature file contains a chain of certificates. One of them has addon ID in its CN component of Subject field.

    This Stack Overflow answer explains how to parse PKCS#7 data using CryptoAPI CryptQueryObject() function.

    For reference Microsoft Support has also more elaborate example of parsing: https://support.microsoft.com/en-us/help/323809/how-to-get-information-from-authenticode-signed-executables.

    Using all these sources, one can compile the following code which would print the required ID:

    #include <windows.h>
    #include <wincrypt.h>
    #pragma comment(lib, "crypt32.lib")
    
    ...
    
    std::string rsaPath = xpiDir + "\\META-INF\\mozilla.rsa";
    std::wstring wRsaPath(rsaPath.begin(), rsaPath.end());
    
    HCERTSTORE hStore = NULL;
    HCRYPTMSG hMsg = NULL;
    BOOL res = CryptQueryObject(
        CERT_QUERY_OBJECT_FILE,
        wRsaPath.c_str(),
        CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
        CERT_QUERY_FORMAT_FLAG_BINARY,
        0,
        NULL,
        NULL,
        NULL,
        &hStore,
        &hMsg,
        NULL
    );
    if (!res) {
        std::cout << "Error decoding PKCS#7 file: " << GetLastError() << std::endl;
        return -1;
    }
    
    PCCERT_CONTEXT next_cert = NULL;
    while ((next_cert = CertEnumCertificatesInStore(hStore, next_cert)) != NULL)
    {
        WCHAR szName[1024];
        // Get subject name
        if (!CertGetNameString(
            next_cert,
            CERT_NAME_SIMPLE_DISPLAY_TYPE,
            0,
            NULL,
            szName,
            1024
        )) {
            std::cout << "CertGetNameString failed.\n";
            return -1;
        }
    
        // only process names looking like IDs, e.g. "CN={212b458b-a608-452b-be1f-a09658163cbf}"
        if (szName[0] == L'{') {
            std::wcout << szName << std::endl;
        }
    }
    
    CryptMsgClose(hMsg);
    CertCloseStore(hStore, 0);
    

    The comparison szName[0] == L'{' is not very reliable, it is only used for the sake of code simplicity. One might want to use better way of detecting addon ID value, e.g. regex.