- Notifications
You must be signed in to change notification settings - Fork40
Get Windows System Root certificates
License
ukoloff/win-ca
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Get Windows System Root certificates forNode.js.
UnlikeRuby,Node.js on WindowsallowsHTTPS requests out-of-box.But it is implemented in a rather bizarre way:
Node uses astatically compiled, manually updated, hardcoded listof certificate authorities,rather than relying on the system's trust store...Read more
It's somewhat non-intuitive under any OS,but Windows differs from most of themby having its own trust store,fully incompatible withOpenSSL.
This package is intended tofetch Root CAs from Windows' store(Trusted Root Certification Authorities)and make them available toNode.js application with minimal efforts.
- No internet access is required at all
- Windows store is updated automatically (in most modern environments)
- Manually installed Root certificates are used
- Enterprise trusted certificates (GPO etc.) are made available too
For 95% of users:
- Just say
npm install --save win-ca
- Then call
require('win-ca')
. - That's it!
If you need more -proceed toAPIsection below.
By the way,win-ca
is safe to be usedunder other OSes (not M$ Windows).It does nothing there.
win-ca
was adapted to run inside Electron applicationswith no additional configuration(asar supported).
SeeMinimal Electron application using win-cafor usage example.
Specialextension forVS Codewas created to importwin-ca
in context of VS Code's Extension Host.
Since all VS Code extensions share the same process,root certificates imported by one of themare immediately available to others.This can allow VS Code extensions to connect to(properly configured)intranet sites from Windows machines.
Click to view...
First versions ofwin-ca
opened Windows'Trusted Root Certificate Store,fetched certificates,deduplicated them and installed tohttps.globalAgent.options.ca
,so they are automatically used for allrequests with Node.js'https
module.
But sometimes one needs toget these certificates todo something else.For that case,full featured API was devised.It is the only functionwith numerous parametersand operation modes, eg:
constca=require('win-ca')rootCAs=[]// Fetch all certificates in PEM formatca({format:ca.der2.pem,ondata:crt=>rootCAs.push(crt)})
win-ca
offers three ways of importing:
- Regular
require('win-ca')
- Fallback
require('win-ca/fallback')
- Pure API
require('win-ca/api')
They all export the same API,but differ in initialization:
win-ca
does fetch certificates fromRoot
store,saves them to diskand makes them available tohttps
module with no effort.win-ca/fallback
does the same,but it never usesN-APIfor fetching certificates,so it should workin all versions of Node.jsas well as inside Electron application.win-ca/api
doesnothing,just exports API,so you decide yourselfwhat to do.
API function may be called with no parameters,but that makes little sense.One should pass it object with some fields, ie:
format
defines representation of certificates to fetch.Available values are:Constant Value Meaning der2.der 0 DER-format (binary, Node'sBuffer) der2.pem 1 PEM-format (text, Base64-encoded) der2.txt 2 PEM-format plus some laconic header der2.asn1 3 ASN.1-parsed certificate der2.x509 4 Certificate in node-forge
format (RSA only!)Default value is
der
.See alsoder2 function below.
store
-which Windows' store to use.Default isRoot
(ieTrusted Root Certification Authorities).Windows has a whole lot of Certificatestores (eg
Root
,CA
,My
,TrustedPublisher
etc.)One can list certificates fromany of them(knowing its name)or several stores at once(using array forstore
parameter).varlist=[]require('win-ca/api')({store:['root','ca'],ondata:list})
unique
whether certificates listshould be deduplicated.Default istrue
(no duplicates returned).Use
{unique: false}
to see all certificatesin store.ondata
- callback fired for each certificate found.Every certificate will be converted to
format
and passed as the first (the only) parameter.As a syntactic sugar,array can be passed instead of function,it will be populated with certificates.
onend
- callback fired (with no parameters) at the end of retrievalUseful for asynchronous invocations,but works in any case.
fallback
- boolean flag,indicatingN-APIshouldn't be usedeven if it is available.Default value depends on Node.js version(4, 5 and 7
{fallback: true}
;modern versions{fallback: false}
).It is alsotrue
if Electron is detected.Finally, if
win-ca
has been required aswin-ca/fallback
,default value for this flag is alsoset totrue
.Note, that one can forceN-API by setting
{fallback: false}
,but if Node.js cannot proceed,exception will be thrown.It can be catched,but Node.js will nevertheless remain in unstable state,so beware.async
- boolean flag to make retrieval process asynchronous(false
by default)If
true
, API call returns immediately,certificates will befetched later and feed toondata
callback.Finallyonend
callback will be called.generator
- boolean flag to emulate ES6 generator(default:false
)If called with this flag,ES6 iterator object is immediatelyreturned(regular or asynchronous -according to
async
flag).constca=require('win-ca/api')// Iteratefor(letderofca({generator:true})){// Process(der)}// Or thus (Node.js v>=6)letlist=[...ca({generator:true})]// Or even (Node.js v>=10)forawait(letderofca({generator:true,async:true})){// await Process(der)}
Note, that if callbacks are set alongwith
generator
flag,they will bealso fired.inject
- how to install certificates(default:false
, ie just fetch from store, do not install)If set to
true
,certificated fetchedwill be also added tohttps.globalAgent.options.ca
(in PEM format, regardless offormat
parameter),so all subsequent callstohttps
client methods(https.request, https.get etc.)will silently use theminstead of built-in ones.If set to
'+'
,newexperimentalmethod is used instead:tls.createSecureContext()
is patched andfetched certificatesare usedin addition tobuilt-in ones(and not only forhttps
,but for all secure connections).Injection mode can be laterchanged (or disabled)with.inject()helper function.
save
- how to save certificates to disk(default:false
, ie useno I/O at all)If set to string, or array of strings,they will be treated aslist of candidate folders to save certificates to.First one that exists or can be(recursively) created will be used.
If no valid folder path found,saving will be silently discarded.
If
{save: true}
used,predefined list of folders will be tried:pem
folder insidewin-ca
module itself.local/win-ca/pem
folder inside user's profile
Certificates will be stored into the folder in two formats:
- Each certificate as separate text file with special file name(mimics behavour ofOpenSSL's
c_rehash
utility) -suitable forSSL_CERT_DIR
- All certificates in single
roots.pem
file -suitable forSSL_CERT_FILE
If
win-ca
is required not viawin-ca/api
,it calls itself with{inject: true, save: true}
and additionaly setsca.path
fieldandSSL_CERT_DIR
environment variableto the folder with certificates saved.onsave
- callback called at the end of saving(ifsave
is truthy).Path to a folder is passed to callback,or no parameters (
undefined
)if it has been impossible to save certificates to disk.
Some internal functions are exposed:
varcertificate=ca.der2(format,certificate_in_der_format)
Converts certificate from DERtoformatspecified in first parameter.
Function.der2()
is curried:
vartoPEM=ca.der2(ca.der2.pem)varpem=toPEM(der)
varhash=ca.hash(version,certificate_in_der_format)
Gives certificate hash(aka X509_NAME_hash),ie 8-character hexadecimal string,derived from certificate subject.
If version (first parameter) is 0,an old algorithm is used(aka X509_NAME_hash_old, used in OpenSSL v0.*),else - the new one(X509_NAME_hash of OpenSSL v1.*).
Function.hash()
is also curried:
varhasher=ca.hash()console.log(hasher(der))
ca.inject(mode)// or:ca.inject(mode,array_of_certificates)
Manages the waycertificates arepassed to other modules.
This function is internally called by APIwhen{inject:}
parameter used.
First argument (mode
) is injection mode:
false
: no injection, built-in certificates are usedtrue
: put certificates tohttps.globalAgent.options.ca
and use theminstead of built-in ones forhttps
module'+'
: newexperimental mode:tls.createSecureContext()
is patchedand certificates are usedalong with built-in ones.This mode should affect all secure connections,not justhttps
module.
Second parameter (array_of_certificates
)is list of certificates to inject.If it is omitted,previous list is used(only inject mode is changed).
For example,simplest way to test newinjection mode is:
constca=require('win-ca')// Fetch certificates and start injecting (old way)ca.inject('+')// Switch to new injection mode
Note,that this function should be calledbefore first secure connection is established,since every secure connection populatesdifferent caches,that are extremely hard to invalidate.Changing injection mode in themiddle of secure communicationcan lead to unpredictable results.
Applications that usewin-ca
are sometimes packed / bundled.In this case one should find appropriateplace for binary utilityroots.exe
(used in fallback mode,which is always the case with Electron apps)and then makewin-ca
to find the binary.
Function.exe()
is intended to provide thisfunctionality.You must call itbefore first invocation of library itself,eg:
varca=require('win-ca/api')ca.exe('/full/path/to/roots.exe')ca({fallback:true,inject:true})
.exe()
with no parameters switches todefault location(insidelib
folder).In any case it returns previouspath toroots.exe
:
console.log(require('win-ca').exe()) // Where is my root.exe?
Click to view...
win-ca
v2 had another API,which is preserved for compatibility,but discouraged to use.It consists of three functions:
- Synchronous:
.all()
.each()
- Asynchronous:
.each.async()
var ca = require('win-ca')do.something.with(ca.all(ca.der2.pem))
Note:
All three yieldcertificatesinnode-forge's formatby default(unlikemodern API,that returns DERif unspecified by user).
Unfortunately,
node-forge
at the time of writing is unable toparse non-RSA certificates(namely, ECC certificates becoming more popular).If yourTrusted Root Certification Authorities storecontains modern certificates,legacy API callswill throw exception.To tackle the problem -pass themformatas the first parameter..all()
deduplicatescertificates (likeregular API),while both.each
callsmay return duplicates({unique: false}
applied)Root
store always used(no way forstore:
option)Both
.each
calls require callback(with optionalformat
)Synchronous
.each()
callback gets singleargument - certificate(in specified format)varca=require('win-ca')ca.each(ca.der2.x509,crt=>console.log(crt.serialNumber))
Asynchronous
.each.async()
callbackgets two parameters:error
(which is alwaysundefined
in this version)result
- certificate in requestedformat
orundefined
to signal end of retrieval
letca=require('win-ca')ca.each.async((error,crt)=>{if(error)throwerror;if(crt)console.log(forge.pki.certificateToPem(crt))elseconsole.log("That's all folks!")})
Current version usesN-API,so it can be used inNode.js versions with N-API support,i.e. v6 and all versions starting from v8.
Thanks to N-API, it is possible to precompileWindows DLL and save it to package,so no compilation is needed at installation time.
For other Node.js versions(v4, 5 or 7)specialfallback utility is calledin the background to fetch the list anyway.
If you wish to use this fallback engine(even for modern Node.js),you can
require('win-ca/fallback')
Windows 10 tends tohave only a few certificates initsTrusted Root Certification Authorities storeandlazily add them to it on first use.
If your OS does so,win-ca
will still help toconnect to your own sites(protected by self-signed certificates,or by the ones, distributed with GPO),but will make connection towell-known sites(like Google or Twitter) impossible!
The simplest remedy is toonce open desired site inInternet Explorer / Google Chrome(certificate will besilently addedto Root store).
Another option is to switch to newexperimentalinjection method:
require('win-ca').inject('+')
If you usewin-ca
in some Electron app or VS Code extension,be warned thatnode_modules/win-ca/pem
folderishighly likely to be packed into your bundlewith all root certificates on development machine.
You had better remove said folderbefore publishing(eg. inprepack
npm script if it applies).
- npm install
- npm run pretest
- npm runnvm$
- npm publish
This builds bothx86
andx64
versions withN-API support.For older Node.js versions standalone binary utility is built.
- OpenSSL::Win::Root for Ruby version
- mac-ca for Mac OS version
Usesnode-forgeand used to usenode-ffi-napi (ancestor ofnode-ffi).
About
Get Windows System Root certificates