{"id":15044985,"url":"https://github.com/ukoloff/win-ca","last_synced_at":"2025-05-15T18:05:17.122Z","repository":{"id":15238662,"uuid":"73288049","full_name":"ukoloff/win-ca","owner":"ukoloff","description":"Get Windows System Root certificates","archived":false,"fork":false,"pushed_at":"2025-05-12T13:04:53.000Z","size":2372,"stargazers_count":112,"open_issues_count":12,"forks_count":41,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-05-12T14:32:19.014Z","etag":null,"topics":["certificate-authority","electron","n-api","napi","node-forge","node-js","openssl","pem","root-cas","root-certificate","root-certificates","tls","tls-certificate","truststore","vscode","vscode-extension","windows","x509"],"latest_commit_sha":null,"homepage":null,"language":"LiveScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ukoloff.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-11-09T13:49:49.000Z","updated_at":"2025-03-26T07:21:27.000Z","dependencies_parsed_at":"2023-10-16T22:29:24.737Z","dependency_job_id":"889c5880-9871-4784-bd06-675517143709","html_url":"https://github.com/ukoloff/win-ca","commit_stats":{"total_commits":461,"total_committers":7,"mean_commits":65.85714285714286,"dds":0.0195227765726681,"last_synced_commit":"dcbfafa746f6924ba4445bec6aac8d61bf22225f"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ukoloff%2Fwin-ca","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ukoloff%2Fwin-ca/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ukoloff%2Fwin-ca/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ukoloff%2Fwin-ca/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ukoloff","download_url":"https://codeload.github.com/ukoloff/win-ca/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254394720,"owners_count":22063984,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["certificate-authority","electron","n-api","napi","node-forge","node-js","openssl","pem","root-cas","root-certificate","root-certificates","tls","tls-certificate","truststore","vscode","vscode-extension","windows","x509"],"created_at":"2024-09-24T20:51:18.843Z","updated_at":"2025-05-15T18:05:17.074Z","avatar_url":"https://github.com/ukoloff.png","language":"LiveScript","readme":"# win-ca\n\n[![Build status](https://ci.appveyor.com/api/projects/status/e6xhpp9d7aml95j2?svg=true)](https://ci.appveyor.com/project/ukoloff/win-ca)\n[![NPM version](https://badge.fury.io/js/win-ca.svg)](http://badge.fury.io/js/win-ca)\n[![Store Roots](https://github.com/ukoloff/win-ca/workflows/Store%20Roots/badge.svg)](https://github.com/ukoloff/win-ca/actions)\n\nGet Windows System Root certificates for [Node.js].\n\n## Rationale\n\nUnlike [Ruby][], [Node.js][] on Windows **allows**\nHTTPS requests out-of-box.\nBut it is implemented in a rather bizarre way:\n\n\u003e Node uses a\n\u003e [statically compiled, manually updated, hardcoded list][node.pem]\n\u003e of certificate authorities,\n\u003e rather than relying on the system's trust store...\n\u003e [Read more][node/4175]\n\nIt's somewhat non-intuitive under any OS,\nbut Windows differs from most of them\nby having its own trust store,\nfully incompatible with [OpenSSL].\n\nThis package is intended to\nfetch Root CAs from Windows' store\n(*Trusted Root Certification Authorities*)\nand make them available to\n[Node.js] application with minimal efforts.\n\n### Advantages\n\n- No internet access is required at all\n- Windows store is updated automatically (in most modern environments)\n- Manually installed Root certificates are used\n- Enterprise trusted certificates (GPO etc.) are made available too\n\n## Usage\n\nFor 95% of users:\n\n1. Just say `npm install --save win-ca`\n2. Then call `require('win-ca')`.\n3. That's it!\n\nIf you need more -\nproceed to [API](#api)\nsection below.\n\nBy the way,\n`win-ca` is safe to be used\nunder other OSes (not M$ Windows).\nIt does nothing there.\n\n### Electron\n`win-ca` was adapted to run inside Electron applications\nwith no additional configuration\n([asar] supported).\n\nSee\n[Minimal Electron application using win-ca][electron-win-ca]\nfor usage example.\n\n### VS Code extension\n\nSpecial [extension](vscode) for [VS Code]\nwas created to import `win-ca`\nin context of VS Code's Extension Host.\n\nSince all VS Code extensions share the same process,\nroot certificates imported by one of them\nare immediately available to others.\nThis can allow VS Code extensions to connect to\n(properly configured)\nintranet sites from Windows machines.\n\n## API\n\u003cdetails\u003e\n\u003csummary\u003e\nClick to view...\n\u003c/summary\u003e\n\nFirst versions of `win-ca`\nopened Windows' *Trusted Root Certificate Store*,\nfetched certificates,\ndeduplicated them and installed to\n`https.globalAgent.options.ca`,\nso they are automatically used for all\nrequests with Node.js' `https` module.\n\nBut sometimes one needs to\nget these certificates to\ndo something else.\nFor that case,\nfull featured API was devised.\nIt is the only function\nwith numerous parameters\nand operation modes, eg:\n\n```js\nconst ca = require('win-ca')\n\nrootCAs = []\n// Fetch all certificates in PEM format\nca({\n  format: ca.der2.pem,\n  ondata: crt =\u003e rootCAs.push(crt)\n})\n```\n\n### Entry points\n\n`win-ca` offers three ways of importing:\n\n1. Regular `require('win-ca')`\n2. Fallback `require('win-ca/fallback')`\n3. Pure API `require('win-ca/api')`\n\nThey all export the same API,\nbut differ in initialization:\n\n1. `win-ca` *does* fetch certificates from\n`Root` store,\nsaves them to disk\nand makes them available to\n`https` module with no effort.\n\n2. `win-ca/fallback` does the same,\nbut it never uses [N-API](#n-api)\nfor fetching certificates,\nso it should work\nin all versions of Node.js\nas well as inside Electron application.\n\n3. `win-ca/api` does *nothing*,\njust exports API,\nso you decide yourself\nwhat to do.\n\n## API Parameters\n\nAPI function may be called with no parameters,\nbut that makes little sense.\nOne should pass it object with some fields, ie:\n\n- `format`\n  defines representation of certificates to fetch.\n  Available values are:\n\n  | Constant | Value | Meaning\n  |---|---:|---\n  |der2.der | 0 | DER-format (binary, Node's [Buffer][])\n  |der2.pem | 1 | PEM-format (text, Base64-encoded)\n  |der2.txt | 2 | PEM-format plus some \u003cabbr title=\"This is SPARTA!!!\"\u003elaconic\u003c/abbr\u003e header\n  |der2.asn1| 3 | ASN.1-parsed certificate\n  |der2.x509| 4 | Certificate in `node-forge` format (RSA only!)\n\n  Default value is `der`.\n\n  See also [der2](#der2) function below.\n\n- `store` -\n  which Windows' store to use.\n  Default is `Root`\n  (ie *Trusted Root Certification Authorities*).\n\n  Windows has a whole lot of Certificate\n  stores (eg `Root`, `CA`, `My`, `TrustedPublisher` etc.)\n  One can list certificates from\n  any of them\n  (knowing its name)\n  or several stores at once\n  (using array for `store` parameter).\n\n  ```js\n  var list = []\n  require('win-ca/api')({store: ['root', 'ca'], ondata: list})\n  ```\n\n- `unique`\n  whether certificates list\n  should be deduplicated.\n  Default is `true`\n  (no duplicates returned).\n\n  Use `{unique: false}`\n  to see all certificates\n  in store.\n\n- `ondata` - callback fired for each certificate found.\n\n  Every certificate will be converted to `format`\n  and passed as the first (the only) parameter.\n\n  As a syntactic sugar,\n  array can be passed instead of function,\n  it will be populated with certificates.\n\n- `onend` - callback fired (with no parameters) at the end of retrieval\n\n  Useful for asynchronous invocations,\n  but works in any case.\n\n- `fallback` - boolean flag,\n  indicating [N-API](#n-api)\n  shouldn't be used\n  even if it is available.\n\n  Default value depends on Node.js version\n  (4, 5 and 7 `{fallback: true}`;\n  modern versions `{fallback: false}`).\n  It is also `true` if Electron is detected.\n\n  Finally, if `win-ca` has been required as\n  `win-ca/fallback`,\n  default value for this flag is also\n  set to `true`.\n\n  Note, that one can force [N-API](#n-api) by setting\n  `{fallback: false}`,\n  but if Node.js cannot proceed,\n  exception will be thrown.\n  It can be catched,\n  but Node.js will nevertheless remain in unstable state,\n  so beware.\n\n- `async` - boolean flag to make retrieval process asynchronous\n  (`false` by default)\n\n  If `true`, API call returns immediately,\n  certificates will be\n  fetched later and feed to `ondata` callback.\n  Finally `onend` callback will be called.\n\n- `generator` - boolean flag to emulate ES6 generator\n  (default: `false`)\n\n  If called with this flag,\n  ES6 iterator object is immediately\n  returned\n  (regular or asynchronous -\n  according to `async` flag).\n\n  ```js\n  const ca = require('win-ca/api')\n\n  // Iterate\n  for (let der of ca({generator: true})) {\n    // Process(der)\n  }\n\n  // Or thus (Node.js v\u003e=6)\n  let list = [...ca({generator: true})]\n\n  // Or even (Node.js v\u003e=10)\n  for await(let der of ca({generator: true, async: true})) {\n    // await Process(der)\n  }\n  ```\n\n  Note, that if callbacks are set along\n  with `generator` flag,\n  they will be *also* fired.\n\n- `inject` - how to install certificates\n  (default: `false`, ie just fetch from store, do not install)\n\n  If set to `true`,\n  certificated fetched\n  will be also added to\n  `https.globalAgent.options.ca`\n  (in PEM format, regardless of `format` parameter),\n  so all subsequent calls\n  to `https` client methods\n  (https.request, https.get etc.)\n  will silently use them\n  *instead* of built-in ones.\n\n  If set to `'+'`,\n  new *experimental*\n  method is used instead:\n  `tls.createSecureContext()`\n  is patched and\n  fetched certificates\n  are used *in addition* to\n  built-in ones\n  (and not only for `https`,\n  but for all secure connections).\n\n  Injection mode can be later\n  changed (or disabled)\n  with [.inject()](#inject)\n  helper function.\n\n- `save` - how to save certificates to disk\n  (default: `false`, ie use *no* I/O at all)\n\n  If set to string, or array of strings,\n  they will be treated as\n  list of candidate folders to save certificates to.\n  First one that exists or can be\n  (recursively) created will be used.\n\n  If no valid folder path found,\n  saving will be silently discarded.\n\n  If `{save: true}` used,\n  predefined list of folders will be tried:\n    + `pem` folder inside `win-ca` module itself\n    + `.local/win-ca/pem` folder inside user's profile\n\n  Certificates will be stored into the folder in two formats:\n    + Each certificate as separate text file with special file name\n      (mimics behavour of [OpenSSL]'s `c_rehash` utility) -\n      suitable for `SSL_CERT_DIR`\n    + All certificates in single `roots.pem` file -\n      suitable for `SSL_CERT_FILE`\n\n  If `win-ca` is required not via `win-ca/api`,\n  it calls itself with `{inject: true, save: true}`\n  and additionaly sets `ca.path` field\n  and `SSL_CERT_DIR` environment variable\n  to the folder with certificates saved.\n\n- `onsave` - callback called at the end of saving\n  (if `save` is truthy).\n\n  Path to a folder is passed to callback,\n  or no parameters (`undefined`)\n  if it has been impossible to save certificates to disk.\n\n## Helper functions\n\nSome internal functions are exposed:\n\n### der2\n\n```js\nvar certificate = ca.der2(format, certificate_in_der_format)\n```\n\nConverts certificate from DER\nto\n[format](#api-parameters)\nspecified in first parameter.\n\nFunction `.der2()` is curried:\n\n```js\nvar toPEM = ca.der2(ca.der2.pem)\n\nvar pem = toPEM(der)\n```\n\n### hash\n```js\nvar hash = ca.hash(version, certificate_in_der_format)\n```\nGives certificate hash\n(aka X509_NAME_hash),\nie 8-character hexadecimal string,\nderived from certificate subject.\n\nIf version (first parameter) is 0,\nan old algorithm is used\n(aka X509_NAME_hash_old, used in OpenSSL v0.\\*),\nelse - the new one\n(X509_NAME_hash of OpenSSL v1.\\*).\n\nFunction `.hash()` is also curried:\n\n```js\nvar hasher = ca.hash()\nconsole.log(hasher(der))\n```\n\n### inject\n```js\nca.inject(mode)\n// or:\nca.inject(mode, array_of_certificates)\n```\n\nManages the way\ncertificates are\npassed to other modules.\n\nThis function is internally called by API\nwhen `{inject:}` parameter used.\n\nFirst argument (`mode`) is injection mode:\n\n- `false`: no injection, built-in certificates are used\n\n- `true`: put certificates to `https.globalAgent.options.ca`\n  and use them *instead* of built-in ones for `https` module\n\n- `'+'`: new *experimental* mode:\n  `tls.createSecureContext()` is patched\n  and certificates are used\n  *along with* built-in ones.\n  This mode should affect all secure connections,\n  not just `https` module.\n\nSecond parameter (`array_of_certificates`)\nis list of certificates to inject.\nIf it is omitted,\nprevious list is used\n(only inject mode is changed).\n\nFor example,\nsimplest way to test new\ninjection mode is:\n```js\nconst ca = require('win-ca') // Fetch certificates and start injecting (old way)\n\nca.inject('+') // Switch to new injection mode\n```\n\nNote,\nthat this function should be called\nbefore first secure connection is established,\nsince every secure connection populates\ndifferent caches,\nthat are extremely hard to invalidate.\nChanging injection mode in the\nmiddle of secure communication\ncan lead to unpredictable results.\n\n### exe\n\nApplications that use `win-ca`\nare sometimes packed / bundled.\nIn this case one should find appropriate\nplace for binary utility `roots.exe`\n(used in fallback mode,\nwhich is always the case with Electron apps)\nand then make `win-ca` to find the binary.\n\nFunction `.exe()` is intended to provide this\nfunctionality.\nYou must call it **before** first invocation of library itself,\neg:\n```js\nvar ca = require('win-ca/api')\n\nca.exe('/full/path/to/roots.exe')\nca({fallback: true, inject: true})\n```\n\n`.exe()` with no parameters switches to\ndefault location\n(inside `lib` folder).\nIn any case it returns previous\npath to `roots.exe`:\n```\nconsole.log(require('win-ca').exe()) // Where is my root.exe?\n```\n\n## Legacy API\n\u003cdetails\u003e\n\u003csummary\u003e\nClick to view...\n\u003c/summary\u003e\n\n`win-ca` v2 had another API,\nwhich is preserved for compatibility,\nbut discouraged to use.\nIt consists of three functions:\n\n* Synchronous:\n  + `.all()`\n  + `.each()`\n* Asynchronous:\n  + `.each.async()`\n\n```\nvar ca = require('win-ca')\n\ndo.something.with(ca.all(ca.der2.pem))\n```\n\nNote:\n1. All three yield\n    certificates\n    in [node-forge][]'s format\n    by default\n    (unlike [modern API](#api),\n    that returns DER\n    if unspecified by user).\n\n    Unfortunately, `node-forge` at the time of writing is unable to\n    parse non-RSA certificates\n    (namely, ECC certificates becoming more popular).\n    If your *Trusted Root Certification Authorities* store\n    contains modern certificates,\n    legacy API calls\n    will throw exception.\n    To tackle the problem -\n    pass them [format](#api-parameters)\n    as the first parameter.\n\n2. `.all()` deduplicates\n  certificates (like [regular API](#api)),\n  while both `.each` calls\n  may return duplicates\n  (`{unique: false}` applied)\n\n3. `Root` store always used\n  (no way for `store:` option)\n\n4. Both `.each` calls require callback\n    (with optional `format`)\n\n    Synchronous `.each()` callback gets single\n    argument - certificate\n    (in specified format)\n\n    ```js\n      var ca = require('win-ca')\n      ca.each(ca.der2.x509, crt=\u003e\n        console.log(crt.serialNumber)\n      )\n    ```\n\n    Asynchronous `.each.async()` callback\n    gets two parameters:\n      + `error` (which is always `undefined` in this version)\n      + `result` - certificate in requested `format`\n        or `undefined` to signal end of retrieval\n\n    ```js\n    let ca = require('win-ca')\n\n    ca.each.async((error, crt)=\u003e {\n      if (error) throw error;\n      if(crt)\n        console.log(forge.pki.certificateToPem(crt))\n      else\n        console.log(\"That's all folks!\")\n    })\n    ```\n\n\u003c/details\u003e\n\n## N-API\n\nCurrent version uses [N-API],\nso it can be used in [Node.js versions with N-API support][N-API-support],\ni.e. v6 and all versions starting from v8.\n\nThanks to N-API, it is possible to precompile\n[Windows DLL](n-api/crypt32.cpp) and save it to package,\nso no compilation is needed at installation time.\n\nFor other Node.js versions\n(v4, 5 or 7)\nspecial [fallback utility](n-api/roots.c) is called\nin the background to fetch the list anyway.\n\nIf you wish to use this fallback engine\n(even for modern Node.js),\nyou can\n```js\nrequire('win-ca/fallback')\n```\n\u003c/details\u003e\n\n## Caveats\n\nWindows 10 tends to\nhave only a few certificates in\nits *Trusted Root Certification Authorities* store\nand [lazily add them to it on first use][win.lazy].\n\nIf your OS does so,\n`win-ca` will still help to\nconnect to your own sites\n(protected by self-signed certificates,\nor by the ones, distributed with GPO),\nbut will make connection to\nwell-known sites\n(like Google or Twitter) impossible!\n\nThe simplest remedy is to\n*once* open desired site in\nInternet Explorer / Google Chrome\n(certificate will be *silently* added\nto Root store).\n\nAnother option is to switch to new\n*experimental* [injection](#inject) method:\n```js\nrequire('win-ca').inject('+')\n```\n\n### Clear `pem` folder on publish\n\nIf you use `win-ca` in some Electron app or VS Code extension,\nbe warned that\n`node_modules/win-ca/pem` folder\nis *highly likely* to be packed into your bundle\nwith all root certificates on development machine.\n\nYou had better remove said folder\nbefore publishing\n(eg. in `prepack` npm script if it applies).\n\n## Building\n\n- npm install\n- npm run pretest\n- npm run [nvm$]\n- npm publish\n\nThis builds both `x86` and `x64` versions with [N-API](#n-api) support.\nFor older Node.js versions standalone binary utility is built.\n\n## See also\n\n- [OpenSSL::Win::Root][] for Ruby version\n- [mac-ca][] for Mac OS version\n\n## Credits\n\nUses [node-forge][]\nand used to use [node-ffi-napi][] (ancestor of [node-ffi][]).\n\n[node-ffi]: https://github.com/node-ffi/node-ffi\n[node-ffi-napi]: https://github.com/node-ffi-napi/node-ffi-napi\n[node-forge]: https://github.com/digitalbazaar/forge\n[OpenSSL::Win::Root]: https://github.com/ukoloff/openssl-win-root\n[Node.js]: http://nodejs.org/\n[Buffer]: https://nodejs.org/api/buffer.html\n[Ruby]: https://www.ruby-lang.org/\n[node.pem]: https://github.com/nodejs/node/blob/master/src/node_root_certs.h\n[node/4175]: https://github.com/nodejs/node/issues/4175\n[OpenSSL]: https://www.openssl.org/\n[nvm$]: https://github.com/ukoloff/nvms\n[N-API]: https://nodejs.org/api/n-api.html\n[N-API-support]: https://github.com/nodejs/node-addon-api/blob/master/index.js#L17\n[VS Code]: https://code.visualstudio.com/\n[mac-ca]: https://github.com/jfromaniello/mac-ca\n[Electron]: https://electronjs.org/\n[electron-win-ca]: https://github.com/ukoloff/electron-win-ca\n[win.lazy]: https://social.technet.microsoft.com/wiki/contents/articles/3147.pki-certificate-chaining-engine-cce.aspx\n[asar]: https://github.com/electron/asar\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fukoloff%2Fwin-ca","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fukoloff%2Fwin-ca","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fukoloff%2Fwin-ca/lists"}