-
-
Notifications
You must be signed in to change notification settings - Fork 34.4k
tls: use options in getCACertificates() with X509Certificate #59349
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 28 commits
c4ca69e
ee04b40
1b8197b
187c86d
4048b54
eae9df7
e013568
195125f
b1eacfb
603967f
36e8a2e
62ec148
361c799
358b2bd
f9dfc62
cdf69dc
d978079
8cf2dbe
e6de951
da83ccf
10e9225
ab76b14
5e8dd7a
f84c311
a335306
319841f
fd0de18
95c07aa
e2879a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -60,7 +60,11 @@ const { Buffer } = require('buffer'); | |
| const { canonicalizeIP } = internalBinding('cares_wrap'); | ||
| const tlsCommon = require('internal/tls/common'); | ||
| const tlsWrap = require('internal/tls/wrap'); | ||
| const { validateString } = require('internal/validators'); | ||
| const { | ||
| validateOneOf, | ||
| validateString, | ||
| } = require('internal/validators'); | ||
| const { X509Certificate } = require('crypto'); | ||
|
|
||
| // Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations | ||
| // every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more | ||
|
|
@@ -164,23 +168,71 @@ function cacheDefaultCACertificates() { | |
| return defaultCACertificates; | ||
| } | ||
|
|
||
| // TODO(joyeecheung): support X509Certificate output? | ||
| function getCACertificates(type = 'default') { | ||
| validateString(type, 'type'); | ||
|
|
||
| switch (type) { | ||
| case 'default': | ||
| return cacheDefaultCACertificates(); | ||
| case 'bundled': | ||
| return cacheBundledRootCertificates(); | ||
| case 'system': | ||
| return cacheSystemCACertificates(); | ||
| case 'extra': | ||
| return cacheExtraCACertificates(); | ||
| default: | ||
| throw new ERR_INVALID_ARG_VALUE('type', type); | ||
| function getCACertificates(options = undefined) { | ||
| if (typeof options === 'string' || options === undefined) { | ||
| const type = (typeof options === 'string') ? options : 'default'; | ||
|
|
||
| validateString(type, 'type'); | ||
|
|
||
| switch (type) { | ||
|
||
| case 'default': return cacheDefaultCACertificates(); | ||
| case 'bundled': return cacheBundledRootCertificates(); | ||
| case 'system': return cacheSystemCACertificates(); | ||
| case 'extra': return cacheExtraCACertificates(); | ||
| default: throw new ERR_INVALID_ARG_VALUE('type', type); | ||
| } | ||
| } else if (typeof options === 'object' && options !== null) { | ||
| const { | ||
| type = 'default', | ||
| format = 'pem', | ||
| } = options; | ||
|
|
||
| validateString(type, 'type'); | ||
| validateOneOf(format, 'format', ['pem', 'der', 'x509', 'string', 'buffer']); | ||
|
|
||
| let effectiveFormat = format; | ||
| if (format === 'string') { | ||
| effectiveFormat = 'pem'; | ||
| } else if (format === 'buffer') { | ||
| effectiveFormat = 'der'; | ||
| } | ||
|
|
||
| let certs; | ||
| switch (type) { | ||
| case 'default': certs = cacheDefaultCACertificates(); break; | ||
| case 'bundled': certs = cacheBundledRootCertificates(); break; | ||
| case 'system': certs = cacheSystemCACertificates(); break; | ||
| case 'extra': certs = cacheExtraCACertificates(); break; | ||
| default: throw new ERR_INVALID_ARG_VALUE('type', type); | ||
| } | ||
|
|
||
| if (effectiveFormat === 'pem') { | ||
| return certs.map((cert) => { | ||
| if (typeof cert === 'string') { | ||
| return cert; | ||
| } | ||
| return `-----BEGIN CERTIFICATE-----\n${cert.toString('base64').match(/.{1,64}/g).join('\n')}\n-----END CERTIFICATE-----`; | ||
| }); | ||
|
||
| } | ||
|
|
||
| const buffers = certs.map((cert) => { | ||
| if (Buffer.isBuffer(cert)) { | ||
| return cert; | ||
| } | ||
| const base64 = cert.replace(/(?:\s|-----BEGIN CERTIFICATE-----|-----END CERTIFICATE-----)+/g, ''); | ||
| return Buffer.from(base64, 'base64'); | ||
| }); | ||
|
|
||
| if (effectiveFormat === 'der') { | ||
| return buffers; | ||
| } | ||
|
|
||
| return buffers.map((buf) => new X509Certificate(buf)); | ||
|
||
| } | ||
|
|
||
| throw new ERR_INVALID_ARG_TYPE('options', ['string', 'object'], options); | ||
| } | ||
|
|
||
| exports.getCACertificates = getCACertificates; | ||
|
|
||
| function setDefaultCACertificates(certs) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| 'use strict'; | ||
|
|
||
| const common = require('../common'); | ||
| if (!common.hasCrypto) | ||
| common.skip('missing crypto'); | ||
|
|
||
| const assert = require('assert'); | ||
| const tls = require('tls'); | ||
| const { X509Certificate } = require('crypto'); | ||
|
|
||
| { | ||
| const certs = tls.getCACertificates({ type: 'default', format: 'x509' }); | ||
| assert.ok(Array.isArray(certs)); | ||
| assert.ok(certs.length > 0); | ||
| for (const cert of certs) { | ||
| assert.ok(cert instanceof X509Certificate); | ||
| } | ||
| } | ||
|
|
||
| { | ||
| const certs = tls.getCACertificates({ type: 'default', format: 'buffer' }); | ||
| assert.ok(Array.isArray(certs)); | ||
| assert.ok(certs.length > 0); | ||
| for (const cert of certs) { | ||
| assert.ok(Buffer.isBuffer(cert)); | ||
| } | ||
| } | ||
|
|
||
| { | ||
| const certs = tls.getCACertificates({ type: 'default' }); | ||
| assert.ok(Array.isArray(certs)); | ||
| assert.ok(certs.length > 0); | ||
| for (const cert of certs) { | ||
| assert.strictEqual(typeof cert, 'string'); | ||
| assert.ok(cert.includes('-----BEGIN CERTIFICATE-----')); | ||
| } | ||
| } | ||
|
|
||
| { | ||
| assert.throws(() => { | ||
| tls.getCACertificates({ type: 'default', format: 'invalid' }); | ||
| }, { | ||
| name: 'TypeError', | ||
| code: 'ERR_INVALID_ARG_VALUE', | ||
| message: /must be one of/ | ||
| }); | ||
| } | ||
|
|
||
| { | ||
| const certs = tls.getCACertificates({ format: 'buffer' }); | ||
| assert.ok(Array.isArray(certs)); | ||
| assert.ok(certs.length > 0); | ||
| for (const cert of certs) { | ||
| assert.ok(Buffer.isBuffer(cert)); | ||
| } | ||
| } | ||
|
|
||
| { | ||
| assert.throws(() => { | ||
| tls.getCACertificates({ type: 'invalid', format: 'buffer' }); | ||
| }, { | ||
| name: 'TypeError', | ||
| code: 'ERR_INVALID_ARG_VALUE', | ||
| message: "The argument 'type' is invalid. Received 'invalid'" | ||
| }); | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.