简体   繁体   English

Hyperledger Fabric:无法更新节点 SDK 中的证书属性

[英]Hyperledger Fabric: Unable to Update Certificate Attributes in Node SDK

I'm making a block chain application for which I'm using Hyperledger Fabric Node SDK .我正在制作一个使用Hyperledger Fabric Node SDK的区块链应用程序。 When a user signs up then the user's certificate is added to the wallet as an identity.当用户注册时,用户的证书将作为身份添加到钱包中。 Now the attributes that I'm storing in a user's certificate are the email and password .现在我存储在用户证书中的属性是email 和 password Also, the user's password is not stored anywhere else, but only in the certificate.此外,用户的密码不会存储在其他任何地方,而只会存储在证书中。 Now, I also need to update the user's password.现在,我还需要更新用户的密码。

Searching on the internet, I got to know that the attributes in the certificate can be updated using the identityService's update function provided in Node and you don't have to re-enroll a user if you're using the identityService's update function.在互联网上搜索,我知道证书中的属性可以使用 Node 中提供的identityService 的更新 function进行更新,如果您使用的是 identityService 的更新 function,则无需重新注册用户。 The issue is that I tried it and the response showed the updated password.问题是我试过了,响应显示更新的密码。 But then when I checked the certificate, the old password was still there ie it had not been updated.但是当我检查证书时,旧密码仍然存在,即尚未更新。 I'm using the fabric-ca-client package for the FabricCAServices and the x509 package for the x509 certificates.我将fabric-ca-client package 用于 FabricCAServices,将x509 package 用于 x509 证书。

The code with which I am enrolling and registering the user is as follows:我注册和注册用户的代码如下:

let ccp = await getCCP(orgName);
const caURL = await getCaUrl(orgName, ccp)
const ca = new FabricCAServices(caURL);
    
const walletPath = await getWalletPath(orgName);
const wallet = await Wallets.newFileSystemWallet(walletPath);
logger.info(`Wallet path: ${walletPath}`);

const userIdentity = await wallet.get(email); //getting user from the wallet
if (userIdentity) //if found so user is already registered
{
    return "User Already Exists";
}
    
//else user does not exist so checking if admin exists
let adminIdentity = await wallet.get('admin'); //getting admin from wallet
if (!adminIdentity) { //if not found so admin does not exist
    logger.debug('An identity for the admin user "admin" does not exist in the wallet');
    await enrollAdmin(orgName, ccp); //enrolling the admin
    adminIdentity = await wallet.get('admin');
    logger.debug("Admin Enrolled Successfully");
}

//now admin exists, so making a user object for authenticating with the CA(i.e. admin)
const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type);
const adminUser = await provider.getUserContext(adminIdentity, 'admin');
let secret;
try {
    //registering the user, enrolling the user, and importing the new identity into the wallet.
    secret = await ca.register({ affiliation: 'org1.department1', enrollmentID: email, role: 'client', attrs: [{name: 'userType', value: userType, ecert: true},{name: 'password', value: password, ecert: true}]}, adminUser);
} catch (error) {
    return error.message;
}

const enrollment = await ca.enroll({ enrollmentID: email, enrollmentSecret: secret, attr_reqs: [{  name: 'userType', optional: false }, {  name: 'password', optional: false }] });

let x509Identity;
if (orgName == "Org1") {
    x509Identity = {
        credentials: {
            certificate: enrollment.certificate,
            privateKey: enrollment.key.toBytes(),
        },
        mspId: 'Org1MSP',
        type: 'X.509',
    };
} else if (orgName == "Org2") {
    x509Identity = {
        credentials: {
            certificate: enrollment.certificate,
            privateKey: enrollment.key.toBytes(),
        },
        mspId: 'Org2MSP',
        type: 'X.509',
    };
}
await wallet.put(email, x509Identity); //adding user to wallet
return "Registered!";

And the code with which I check the attributes stored in the password is:我检查存储在密码中的属性的代码是:

//Getting wallet path for orgName...
const walletPath = await getWalletPath(orgName);
const wallet = await Wallets.newFileSystemWallet(walletPath);
logger.info(`Wallet path: ${walletPath}`);

//getting this user from the wallet
const userIdentity = await wallet.get(email);
if (userIdentity) { //if found i.e. user is registered
    //parsing certificate to get password
    var issuer = x509.parseCert(userIdentity.credentials.certificate);
    var jsn = issuer.extensions['1.2.3.4.5.6.7.8.1'];
    jsn = jsn.substring(2);
    jsn = (JSON.parse(jsn));
    //here jsn.attrs.password has the password
}

And the code that I'm using to update the certificate attributes is:我用来更新证书属性的代码是:

let ccp = await getCCP(orgName);
const caURL = await getCaUrl(orgName, ccp);
const ca = new FabricCAServices(caURL);

//Getting wallet path for orgName...
const walletPath = await getWalletPath(orgName);
const wallet = await Wallets.newFileSystemWallet(walletPath);
logger.info(`Wallet path: ${walletPath}`);

const userIdentity = await wallet.get(email); //getting this user from the wallet
if (userIdentity) { //if found i.e. user is registered

    //Create a new gateway for connecting to our peer node
    const gateway = new Gateway();
    await gateway.connect(ccp, { wallet, identity: email, discovery: { enabled: true, asLocalhost: true } });

    const identityService = ca.newIdentityService();

    let adminIdentity = await wallet.get('admin'); //getting admin from wallet
    //now making a user object of the admin
    const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type);
    const adminUser = await provider.getUserContext(adminIdentity, 'admin');

    var theIdentityRequest = { enrollmentID: email, affiliation: 'org1.department1', attrs: [ {name: 'userType', value: 'Student', ecert: true},{name: 'password', value: newPassword, ecert: true} ] };

    logger.warn("The Request: ", theIdentityRequest);

    let response = await identityService.update(email, theIdentityRequest, adminUser);
                
    logger.warn("userIdenity attributes: ",response.result.attrs);

    await gateway.disconnect();
}

I want to know why the certificate still has the old password and how to update the password in the certificate.我想知道为什么证书仍然有旧密码以及如何更新证书中的密码。 And I also want to know that does the identityService update the attributes in the x509 certificate or is reenrolling the user necessary for this?而且我还想知道 identityService 是否更新了 x509 证书中的属性,还是为此重新注册了必要的用户?

You can fix it by doing reenroll as you said.您可以按照您所说的reenroll来修复它。

The update command of IdentityService is to update the identity of registered user in CA. IdentityServiceupdate命令是更新 CA 中registered用户的身份。
Since this is not the process of updating the certificate, the only way to obtain a certificate containing the newly modified Attr is to obtain a new certificate (the certificate is the X.509 standard).由于这不是更新证书的过程,因此获取包含新修改的Attr的证书的唯一方法是获取新证书(该证书是 X.509 标准)。


Why does the attr change require a new certificate?为什么 attr 更改需要新证书?

  • Fabric generally uses the X.509 certificate standard method.(when not using idemix) Fabric一般使用X.509证书标准方法。(不使用idemix时)
  • Actually not only Fabric, almost all certificates on the web follow the standard.其实不只是Fabric,几乎所有web上的证书都遵循标准。
  • In Fabric, the Attr is existed in extensions in the X509(v3) certificate and has the following format.在 Fabric 中, Attr存在于 X509(v3) 证书的extensions中,格式如下。
X509v3 extensions:
    ...
    1.2.3.4.5.6.7.8.1:
        {"attrs":{"hf.Affiliation":"org1.department1","hf.EnrollmentID":"appUser5","hf.Type":"client","userType":"userType"}}
    ...
  • In other words, when Attr is modified, extensions are modified.换句话说,当Attr被修改时, extensions被修改。
  • In X.509(v3), extenstions are also included in the certificate integrity verification process.在 X.509(v3) 中, extenstions也包含在证书完整性验证过程中。
  • The integrity verification process is implemented based on PKI and Hash , and is provided in the form of attaching the signature signed by the CA to the hashed data (including extensions) to the certificate.完整性验证过程基于PKIHash实现,并以 CA 签署的signature附加到证书的散列数据(包括扩展)的形式提供。
  • That is, if extensions are modified, the signature in the certificate must be modified, which means that a new certificate must be issued .即如果修改了extensions ,则必须修改证书中的signature ,这意味着必须颁发新的证书

Come back to Fabric,回到面料,

  • The reenroll command is an act of newly issuing enrolled user data based on the registered user . reenroll命令是基于registered user newly issuing注册用户数据的行为。
  • After updating , a new certificate is issued through the reenroll command to obtain a certificate that includes new Attrs in the corresponding certificate. updating后,通过reenroll命令颁发新证书,获取对应证书中包含new Attrs的证书。

The following example code has been tested and works.以下示例代码已经过测试并且可以工作。 See this.看到这个。

// registerUser, enrollUser, updateUser, reEnrollUser

/*
 * Copyright IBM Corp. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

'use strict';

const { Wallets } = require('fabric-network');
const FabricCAServices = require('fabric-ca-client');
const fs = require('fs');
const path = require('path');

async function main() {
    try {
        // 0. given, already enrolled 'admin'
        const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
        const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
        const caURL = ccp.certificateAuthorities['ca.org1.example.com'].url;
        const ca = new FabricCAServices(caURL);
        const walletPath = path.join(process.cwd(), 'wallet');
        const wallet = await Wallets.newFileSystemWallet(walletPath);
        const provider = wallet.getProviderRegistry().getProvider('X.509');
        
        // 1. register testUser
        const adminIdentity = await wallet.get('admin');
        const appUser = 'testUser';
        const adminUser = await provider.getUserContext(adminIdentity, 'admin');
        const secret = await ca.register({
                affiliation: 'org1.department2',
                attrs: [{name: 'userType', value: 'userType', ecert: true}],
                enrollmentID: appUser,
                role: 'client'
        }, adminUser);

        // 2. enroll testUser
        const enrollment = await ca.enroll({
                enrollmentID: appUser,
                enrollmentSecret: secret
        });
        const x509Identity = {
                credentials: {
                        certificate: enrollment.certificate,
                        privateKey: enrollment.key.toBytes(),
                },
                mspId: 'Org1MSP',
                type: 'X.509',
        };
        await wallet.put(appUser, x509Identity);

        // 3. update testUser's Identity in Fabric-CA
        const appUserIdentity = await wallet.get(appUser);
        const newAppUser = await provider.getUserContext(appUserIdentity, appUser);
        const identityService = ca.newIdentityService();
        var theIdentityRequest = { enrollmentID: appUser, affiliation: 'org1.department1', attrs: [ {name: 'userType', value: 'Student', ecert: true} ] };
        let response = await identityService.update(appUser, theIdentityRequest, adminUser);
        console.log("userIdenity attributes: ", response.result.attrs);

        // 4. reenroll testUser
        const newEnrollment = await ca.reenroll(newAppUser);
        const newX509Identity = {
                credentials: {
                        certificate: newEnrollment.certificate,
                        privateKey: newEnrollment.key.toBytes(),
                },
                mspId: 'Org1MSP',
                type: 'X.509',
        };
        await wallet.put(`new_${appUser}`, newX509Identity);

    } catch (error) {
        console.error(`Failed to register user "appUser": ${error}`);
        process.exit(1);
    }
}
ls wallet
testUser.id  new_testUser.id

The result of docode the issued certificate ( hf.Affiliation and userType are updated) docode 颁发证书的结果(更新hf.AffiliationuserType

// attrs in 'enroll' Certificate's extensions
{"attrs": "hf.Affiliation":"org1.department2","hf.EnrollmentID":"testUser","hf.Type":"client","userType":"userType"}}

// attrs in 'reenroll' Certificate's extensions
{"attrs":{"hf.Affiliation":"org1.department1","hf.EnrollmentID":"testUser","hf.Type":"client","userType":"Student"}}

[PS] Looking at the Version indicated in the client's identity, it seems that there may be a way to upgrade the existing one, but I have not checked or tried it. [PS] 看客户身份标明的Version ,好像有办法升级现有的,但我没有检查或尝试过。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM