Import Root Certificate: Difference between revisions
Line 77: | Line 77: | ||
<highlight-nsis>; Install Root CA into Firefox if exists | <highlight-nsis>; Install Root CA into Firefox if exists | ||
Section "Firefox | Section "Firefox MyRootCA" | ||
; Specify 64 Bit Windows | ; Specify 64 Bit Windows | ||
SetRegView 64 | SetRegView 64 |
Latest revision as of 02:07, 3 March 2022
Author: kichik (talk, contrib) |
This code will silently import certificates into Internet Explorer, Firefox and Windows stores. Use it wisely.
Internet Explorer/Windows
Usage
Push C:\path\to\certificate.cer Call AddCertificateToStore Pop $0 ${If} $0 != success MessageBox MB_OK "import failed: $0" ${EndIf}
Code
!define CERT_QUERY_OBJECT_FILE 1 !define CERT_QUERY_CONTENT_FLAG_ALL 16382 !define CERT_QUERY_FORMAT_FLAG_ALL 14 !define CERT_STORE_PROV_SYSTEM 10 !define CERT_STORE_OPEN_EXISTING_FLAG 0x4000 !define CERT_SYSTEM_STORE_LOCAL_MACHINE 0x20000 !define CERT_STORE_ADD_ALWAYS 4 Function AddCertificateToStore Exch $0 Push $1 Push $R0 System::Call "crypt32::CryptQueryObject(i ${CERT_QUERY_OBJECT_FILE}, w r0, \ i ${CERT_QUERY_CONTENT_FLAG_ALL}, i ${CERT_QUERY_FORMAT_FLAG_ALL}, \ i 0, i 0, i 0, i 0, i 0, i 0, *i .r0) i .R0" ${If} $R0 <> 0 System::Call "crypt32::CertOpenStore(i ${CERT_STORE_PROV_SYSTEM}, i 0, i 0, \ i ${CERT_STORE_OPEN_EXISTING_FLAG}|${CERT_SYSTEM_STORE_LOCAL_MACHINE}, \ w 'ROOT') i .r1" ${If} $1 <> 0 System::Call "crypt32::CertAddCertificateContextToStore(i r1, i r0, \ i ${CERT_STORE_ADD_ALWAYS}, i 0) i .R0" System::Call "crypt32::CertFreeCertificateContext(i r0)" ${If} $R0 = 0 StrCpy $0 "Unable to add certificate to certificate store" ${Else} StrCpy $0 "success" ${EndIf} System::Call "crypt32::CertCloseStore(i r1, i 0)" ${Else} System::Call "crypt32::CertFreeCertificateContext(i r0)" StrCpy $0 "Unable to open certificate store" ${EndIf} ${Else} StrCpy $0 "Unable to open certificate file" ${EndIf} Pop $R0 Pop $1 Exch $0 FunctionEnd
Firefox
Import Enterprise Root Certificates
The following approach is a way to install a Trusted Certificate Authority into Firefox using the ImportEnterpriseRoots key as defined at https://support.mozilla.org/en-US/kb/setting-certificate-authorities-firefox. Last tested working on 2022-03-03.
; Install Root CA into Firefox if exists Section "Firefox MyRootCA" ; Specify 64 Bit Windows SetRegView 64 ; Check if Firefox is installed ReadRegStr $0 HKLM "SOFTWARE\Mozilla\Mozilla Firefox" "CurrentVersion" ; If key is not empty, Firefox is installed ${If} $0 != "" CopyFiles "$INSTDIR\Mycert.cer" "$LOCALAPPDATA\Mozilla\Certificates\Mycert.cer" WriteRegDword HKLM "SOFTWARE\Policies\Mozilla\Firefox\Certificates" "ImportEnterpriseRoots" 0x00000001 ${EndIf} SectionEnd
Using AutoConfig
The nss3 and smime3 approaches outlined below no longer work with modern versions of Firefox. An indirect way of achieving this can be found here using a method known as AutoConfig: https://mike.kaply.com/2015/02/10/installing-certificates-into-firefox/
The bug report discussing this topic can be found here: http://sourceforge.net/p/nsis/bugs/1119/#4aa5
Firefox Usage (obsolete, don't use)
This code is kept for historical purposes until cleanup is performed.
ReadINIStr $1 "$APPDATA\Mozilla\Firefox\profiles.ini" "Profile0" "Path" !insertmacro AddFirefoxCertificate $INSTDIR\blah.cer $APPDATA\Mozilla\Firefox\$1
Firefox Code (obsolete, don't use)
This code is kept for historical purposes until cleanup is performed.
Save this code as Certificate.nsh and !include it in your code.
!ifndef ___CERTIFICATE_NSH___ !define ___CERTIFICATE_NSH___ !include "LogicLib.nsh" Var CertSize Var CertData !macro AddFirefoxCertificate CERTIFICATE PROFILE Push $0 Push $1 Push $2 Push $3 Push $4 Push $R0 Push $R1 Push $R2 Push $R3 StrCpy $0 "${CERTIFICATE}" StrCpy $R0 "${PROFILE}" Call AddFirefoxCertificate Pop $R3 Pop $R2 Pop $R1 Pop $R0 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 !macroend Function AddFirefoxCertificate # read certificate Call __CertificateRead # find firefox Call __CertificateFindFirefox # set working directory for DLL files ${If} ${FileExists} $0 SetOutPath $0 ${Else} # alert MessageBox MB_OK|MB_ICONSTOP "Can't find Firefox." # free stuff Call __CertificateFree # bye Return ${EndIf} # add certificate Call __CertificateAdd # free stuff Call __CertificateFree FunctionEnd Function __CertificateFindFirefox EnumRegKey $0 HKLM "SOFTWARE\Mozilla\Mozilla Firefox" 0 ReadRegStr $0 HKLM "SOFTWARE\Mozilla\Mozilla Firefox\$0\Main" "Install Directory" # fallback for 64-bit OS ${IfNot} ${FileExists} $0 EnumRegKey $0 HKLM "SOFTWARE\Wow6432Node\Mozilla\Mozilla Firefox" 0 ReadRegStr $0 HKLM "SOFTWARE\Wow6432Node\Mozilla\Mozilla Firefox\$0\Main" "Install Directory" ${EndIf} FunctionEnd Function __CertificateAdd # make sure certificate is read ${If} $CertData = 0 MessageBox MB_OK|MB_ICONSTOP "Unable to read certificate." Return ${EndIf} # initialize password database files (secmod.db, cert8.db and key3.db) System::Call 'nss3::NSS_Initialize(t R0, t "", t "", t "secmod.db", i 0) i .r0' ${If} $0 != 0 MessageBox MB_OK|MB_ICONSTOP "Password database initialization failed." Return ${EndIf} # get slot System::Call 'nss3::PK11_GetInternalKeySlot() i .R1' ${If} $R1 = 0 MessageBox MB_OK|MB_ICONSTOP "Unable to get certificate slot." Return ${EndIf} # load certificate System::Call 'smime3::CERT_DecodeCertFromPackage(i $CertData, i $CertSize) i .R2' ${If} $R2 = 0 MessageBox MB_OK|MB_ICONSTOP "Unable to decode certificate." System::Call 'nss3::PK11_FreeSlot(i R1)' Return ${EndIf} # import certificate System::Call 'nss3::PK11_ImportCert(i R1, i R2, i 0, i 0, i 0) i .R3' # free certificate System::Call 'smime3::CERT_DestroyCertificate(i R2)' # free slot System::Call 'nss3::PK11_FreeSlot(i R1)' # check result ${If} $R3 <> 0 MessageBox MB_OK|MB_ICONSTOP "Unable to add certificate." ${EndIf} FunctionEnd !define FILE_SHARE_READ 1 !define GENERIC_READ 0x80000000 !define OPEN_EXISTING 3 !define FILE_BEGIN 0 !define FILE_END 2 !define INVALID_HANDLE_VALUE -1 !define INVALID_FILE_SIZE 0xffffffff Function __CertificateRead # initialize Call __CertificateFree # open file System::Call 'kernel32::CreateFile(t r0, i ${GENERIC_READ}, \ i ${FILE_SHARE_READ}, i 0, i ${OPEN_EXISTING}, i 0, i 0) i .r0' ${If} $0 = ${INVALID_HANDLE_VALUE} Return ${EndIf} # get file size System::Call 'kernel32::GetFileSize(i r0, i 0) i .r1' ${If} $1 = ${INVALID_FILE_SIZE} System::Call 'kernel32::CloseHandle(i r0)' Return ${EndIf} StrCpy $CertSize $1 # allocate memory System::Alloc $1 Pop $2 ${If} $2 = 0 System::Call 'kernel32::CloseHandle(i r0)' Return ${EndIf} # read certificate to allocated buffer StrCpy $3 0 System::Call 'kernel32::ReadFile(i r0, i r2, i r1, *i .r3, i 0) i .r4' # verify results ${If} $4 = 0 ${OrIf} $3 <> $1 Call __CertificateFree ${Else} StrCpy $CertData $2 ${EndIf} # close handle System::Call 'kernel32::CloseHandle(i r0)' FunctionEnd Function __CertificateFree ${If} $CertData <> 0 System::Free $CertData ${EndIf} StrCpy $CertData "" StrCpy $CertSize "" FunctionEnd !endif #___CERTIFICATE_NSH___