Search code examples
certificatedigital-signaturepkicsr

Web Browser Certificate Enrollment (CSR Generation) and Certificate Download to Smartcard or USB Token


I am developing Web Application for Certifying Authority as a part of which, I need to

  1. Generate asymmetric key pair - Private Key and Public Key in user's smartcard through browser,
  2. create Certificate Signing Request (CSR) and send CSR to Certifying Authority server where user's certificate gets generated.
  3. Then CA Server will send user's certificate to browser which needs to be downloaded to user's SmartCard or USB Token through browser.

How to achieve the same using JavaScript that works in Modern Browsers? Using ActiveX and JavaApplets are not the options.


Solution

  • Disclosure: I work for CISPL, Co. which develops Signer.Digital Browser Extension

    Browser Extension may be used to Enroll Certificate (Generate CSR) and Download Certificate in Windows Certificate Store or Smartcard or USB Token from modern browsers. Browser extension provides JavaScript API which in turn talks to host application running on local machine to do the required operations in smartcard and returns response to JavaScript (or says users web page).

    CSR generated using Browser Javascript API genCSR may be posted to CA Server for certificate generation or to your server if you want self signed certificate. Certificate and Trust Certificate chain received back from the server may be passed to ImportCer to import in the certificate store, smartcard or usb token.

    API Available for Certifying Authorities in Signer.Digital Browser Extension are:

    1. Detect connected smartcard: (Autodetect connected Smartcard or USB Token)

    SignerDigital.getPCSCReaders(onlyConnected = true) //List PCSC Readers, set paramater to false if you want to list all available readers

    Example:

    try 
    {
        var SmartcardReaders = await SignerDigital.getPCSCReaders();
        var SCReaders = JSON.parse(SmartcardReaders);
        console.log(SmartcardReaders);
        console.log(SCReaders.length);
        if (SCReaders.length > 0)
        {
            $("#selSmartcard").empty();     //selSmartcard is HTML dropdown selector
            for (var i = 0; i < SCReaders.length; i++) {
                //ReaderNames are cryptic, convert to user friendly smartcard name
                var SCName = SignerDigital.getSCNameByReaderName(SCReaders[i]);  //Map PCSC ReaderName to User friendly smartcard name
                $("#selSmartcard").append(new Option(SCName));
            }
            
            //If Windows, add "Windows Certificate Store"
            if (SignerDigital.OSName == "Windows")
                $("#selSmartcard").append(new Option("Windows Certificate Store"));
    
            $('#selSmartcard option:eq(1)')
        }
    }
    catch (ErrorMsg) {
        alert(ErrorMsg);
    }
    
    1. Generate CSR: (for Certificate Enrollment in Cert Store, Smartcard or USB Token)

    SignerDigital.genCSR(PKCS11Lib, certSubject, certIssuer, keyBits = 2048, hasgAlgorithm = "SHA256", forceUserPinChangeIfDefault = false, , extensions = null)

    To enforce password policy, viz. force user to change default password set by Smartcard manufacturer, set forceUserPinChangeIfDefault to true

    Sample extensions parameter values:

    {"SubjectAlternativeName":"RFC822Name=cisplapp@gmail.com"} {"SubjectAlternativeName":"DNSName=signer.digital;DNSName=charteredinfo.com;DNSName=multidomaincert.test"} {"SubjectAlternativeName":"URI=https://web.signer.digital;URI=https://help.signer.digital"}

    1. Import / Download Certificate (Import User Certificate and Trust Certificate Chain to Cert Store, Smartcard or USB Token)

    SignerDigital.importCer(PKCS11Lib, b64Payload, certIssuer)

    Json Model for b64Payload param above is: (Base64 of Json of below model)

    public class ImportCertReq
    {
        public string UserCertB64 ;     //May be null to just import Trust Chain
        public List<string> TrustChainB64;  //May be null to just import USer Certificate
    }
    

    Json Model for success Response from importCer promise is:

    public class ImportCertResp
    {
        public bool IsSuccessUserCertImport;
        public string UserCertImportOutcome; 
        public int TrustChainImportCount; 
        public string TrustChainImportOutcome; 
    }
    

    Generate CSR and Import Certificate api uses PKCS#11 library of smartcard or usb token for combability across OS. Thus, requires smartcard drivers to be installed on user's windows pc before using these JavaScript API. For using Windows Certificate Store, pass PKCS11Lib as "Microsoft Enhanced RSA and AES Cryptographic Provider".

    Other useful properties and methods in Signer.Digital Extension

    1. SignerDigital.getHostDetails() //Check for SDHostVersion >= 2 for genCSR and certImport API to work

    Response Model:

    HostDetails 
    {
        public string OS ;
        public string OSPlatform;
        public string SDHostType ;
        public string SDHostVersion ;
        public DateTime? UpdateCheckedOn ;
        public int CheckForUpdateAfterDays ;
    }
    
    1. SignerDigital.OSName

    2. SignerDigital.OSSupported

    3. SignerDigital.getPkcsLibByProvider(ProviderName)

    4. SignerDigital.getSCNameByReaderName(ReaderName) //ReaderName obtained using promise getPCSCReaders() as listed in point 1 above.

    5. SignerDigital.getPkcsLibBySCName(SCName)

    You may refer to SO Answer for other Certificate, Signing and Encryption/Decryption JavaScript APIs. These API uses Windows CSP and on Linux uses PKCS#11.

    Above API may be tested live Here

    Signer.Digital Generate CSR and Download Certificate Flow

    Signer.Digital Browser Generate CSR and Download Certificate Flow