Skip to content

Commit a403629

Browse files
committed
Update auth header token for CA (stitch)
When interacting with Fabric CA REST services, utilize the updated auth header token format that includes the URL path and method. The old format has been deprecated for a long time (since Fabric CA v1.4.0) since the new format is more secure. New versions of Fabric CA (v1.5.14 and later) will not support the old format by default (although they can still support the old format by setting FABRIC_CA_SERVER_COMPATIBILITY_MODE_V1_3=true). Signed-off-by: David Enyeart <enyeart@us.ibm.com>
1 parent b624bfa commit a403629

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

packages/stitch/src/libs/ca_lib.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ export { getCaIdentities, scGenCSR, getCaAffiliations, registerCaIdentity, enrol
3838
function getCaIdentities(opts: CaInput, cb: Function) {
3939
const options = JSON.parse(JSON.stringify(opts));
4040
options.body_obj = null; // set null for token gen
41+
// set path and method for token gen
42+
options.path = build_ca_path(options, '/api/v1/identities');
43+
options.method = 'GET';
4144

4245
let called_cb = false;
4346
generateCaAuthToken(options, (_: any, token: string) => {
@@ -80,6 +83,9 @@ function getCaIdentities(opts: CaInput, cb: Function) {
8083
function getCaAffiliations(opts: CaInput, cb: Function) {
8184
const options = JSON.parse(JSON.stringify(opts));
8285
options.body_obj = null; // set null for token gen
86+
// set path and method for token gen
87+
options.path = build_ca_path(options, '/api/v1/affiliations');
88+
options.method = 'GET';
8389

8490
let called_cb = false;
8591
generateCaAuthToken(options, (_: any, token: string) => {
@@ -160,6 +166,9 @@ function registerCaIdentity(opts: CaReg, cb: Function) {
160166
type: options.new_identity.type,
161167
max_enrollments: Number(options.new_identity.max_enrollments)
162168
};
169+
// set path and method for token gen
170+
options.path = build_ca_path(options, '/api/v1/identities');
171+
options.method = 'POST';
163172

164173
let called_cb = false;
165174
generateCaAuthToken(options, (_: any, token: string) => {
@@ -283,6 +292,9 @@ function reenrollCaIdentity(opts: CaInput, cb: Function) {
283292
caName: options.ca_name,
284293
certificate_request: csrPEM,
285294
};
295+
// set path and method for token gen
296+
options.path = build_ca_path(options, '/api/v1/reenroll');
297+
options.method = 'POST';
286298

287299
let called_cb = false;
288300
generateCaAuthToken(options, (_: any, token: string) => {
@@ -338,15 +350,18 @@ function get_CN_from_str(str: any) {
338350
*/
339351
function deleteCaIdentity(opts: CaInput, cb: Function) {
340352
const options = JSON.parse(JSON.stringify(opts));
353+
const parsed = parseCertificate(opts.client_cert_b64pem);
354+
const enroll_id = opts.enroll_id || get_CN_from_str(parsed.subject_parts.CN);
341355
options.body_obj = null; // set null for token gen
356+
// set path and method for token gen
357+
options.path = build_ca_path(options, '/api/v1/identities/' + enroll_id);
358+
options.method = 'DELETE';
342359

343-
const parsed = parseCertificate(opts.client_cert_b64pem);
344360
if (!parsed || !parsed.subject_parts || !parsed.subject_parts.CN) {
345361
return cb(fmt_ca_err({ funk: 'deleteCaIdentity' }, null, 'unable to delete id b/c cannot find enroll id in cert'), null);
346362
} else {
347363
let called_cb = false;
348364
generateCaAuthToken(options, (_: any, token: string) => {
349-
const enroll_id = opts.enroll_id || get_CN_from_str(parsed.subject_parts.CN);
350365
const fetch_options = {
351366
host: build_ca_url(options, '/api/v1/identities/' + enroll_id),
352367
authorization: token,
@@ -388,6 +403,21 @@ function build_ca_url(opts: { ca_name: string, host: string }, path: string) {
388403
return opts.host;
389404
}
390405

406+
// ------------------------------------------------------------------------------------------------------
407+
// construct the path to use for the ca, same logic as build_ca_url (above) but without the starting host
408+
// ------------------------------------------------------------------------------------------------------
409+
function build_ca_path(opts: { ca_name: string, host: string }, path: string) {
410+
if (opts.ca_name) { // finding the ca name in input obj
411+
return path + '?ca=' + opts.ca_name;
412+
} else {
413+
const parts = opts.host.split('?'); // finding the ca name in url as query param
414+
if (parts && parts.length >= 2) {
415+
return path + '?' + parts[1]; // parts[1] holds the ca name
416+
}
417+
}
418+
return path;
419+
}
420+
391421
// ----------------------------------------------------------------
392422
// Get some JSON data via Fetch - expects json response
393423
// ----------------------------------------------------------------
@@ -505,6 +535,8 @@ interface CaInput {
505535
ext: Ext | null;
506536
enroll_id: string | null;
507537
timeout_ms: number | null;
538+
path: string;
539+
method: string;
508540
}
509541

510542
interface CaReg extends CaInput {

packages/stitch/src/libs/crypto_misc.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ function fmtKey(key: object | string, type: string) {
458458
//------------------------------------------------------------------
459459
// Generate authorization token required for accessing fabric-ca APIs
460460
//------------------------------------------------------------------
461-
function generateCaAuthToken(opts: { client_prv_key_b64pem: string, client_cert_b64pem: string, body_obj: any }, cb: Function) {
461+
function generateCaAuthToken(opts: { client_prv_key_b64pem: string, client_cert_b64pem: string, body_obj: any, path: string, method: string }, cb: Function) {
462462
let prvKeyPem = decode_b64_pem(opts.client_prv_key_b64pem);
463463
let client_cert_b64pem = btoa(decode_b64_pem(opts.client_cert_b64pem)); // decode and encode to catch non encoded certs
464464
let payload = null;
@@ -470,6 +470,11 @@ function generateCaAuthToken(opts: { client_prv_key_b64pem: string, client_cert_
470470
payload = '.' + client_cert_b64pem;
471471
}
472472

473+
if (opts.path && opts.method) {
474+
const s = btoa(opts.path);
475+
payload = opts.method + '.' + s + '.' + payload;
476+
}
477+
473478
scSign({ prvKeyPEM: prvKeyPem, b_msg: utf8StrToUint8Array(payload) }, (_: any, b_signature: any) => { // subtle crypto method does not need the has function
474479
let b64Sign = uint8ArrayToBase64(b_signature);
475480
return cb(null, client_cert_b64pem + '.' + b64Sign);

0 commit comments

Comments
 (0)