Hyperledger Fabric:无法更新 Node SDK 中的证书属性
Hyperledger Fabric: Unable to Update Certificate Attributes in Node SDK
我正在制作一个区块链应用程序,我正在使用 Hyperledger Fabric Node SDK。当用户 注册 时,用户的证书将作为身份添加到钱包中。现在,我存储在用户证书中的属性是 电子邮件和密码 。
此外,用户的密码不会存储在其他任何地方,而只会存储在证书中。
现在,我还需要更新用户密码。
在网上查了一下,才知道证书中的属性可以通过Node自带的identityService的更新功能进行更新,不用重新如果您正在使用 identityService 的更新功能,请注册用户。
问题是我试过了,响应显示了更新后的密码。
但是当我检查证书时,旧密码仍然存在,即它没有更新。
我正在为 FabricCAServices 使用 fabric-ca-client 包,为 x509 证书使用 x509 包。
我注册用户的代码如下:
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!";
我用来检查存储在密码中的属性的代码是:
//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
}
我用来更新证书属性的代码是:
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();
}
我想知道为什么证书还是旧密码,以及如何更新证书中的密码。
而且我还想知道 identityService 是否更新了 x509 证书中的属性,或者是否正在为此重新注册必要的用户?
你可以按照你说的reenroll
来修复它。
IdentityService
的update
命令是更新CA中registered
用户的身份。
由于这不是更新证书的过程,因此获得包含新修改的Attr
的证书的唯一方法是获得新证书(证书是X. 509 标准)。
为什么 attr 更改需要新证书?
- Fabric一般采用X.509证书标准方式。(不使用idemix时)
- 其实不只是Fabric,网上几乎所有的证书都遵循这个标准
- 在 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"}}
...
- 也就是说,修改
Attr
时,修改extensions
。
- 在 X.509(v3) 中,
extenstions
也包含在证书完整性验证过程中。
- 完整性验证过程是基于
PKI
和Hash
实现的,以在散列数据(包括扩展)中附加CA签名的signature
的形式提供) 到证书。
- 即修改了
extensions
,则必须修改证书中的signature
,即需要颁发新的证书。
回到 Fabric,
reenroll
命令是newly issuing
根据registered user
注册用户数据的行为。
updating
后,通过reenroll
命令颁发新证书,获取相应证书中包含new Attrs
的证书
以下示例代码已经过测试并且可以运行。看到这个。
// 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
颁发证书的docode结果
(hf.Affiliation
和 userType
已更新)
// 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"}}
[P.S]看client's identity中的Version
,好像有办法升级现有的,不过我没查过也没试过
我正在制作一个区块链应用程序,我正在使用 Hyperledger Fabric Node SDK。当用户 注册 时,用户的证书将作为身份添加到钱包中。现在,我存储在用户证书中的属性是 电子邮件和密码 。 此外,用户的密码不会存储在其他任何地方,而只会存储在证书中。 现在,我还需要更新用户密码。
在网上查了一下,才知道证书中的属性可以通过Node自带的identityService的更新功能进行更新,不用重新如果您正在使用 identityService 的更新功能,请注册用户。 问题是我试过了,响应显示了更新后的密码。 但是当我检查证书时,旧密码仍然存在,即它没有更新。 我正在为 FabricCAServices 使用 fabric-ca-client 包,为 x509 证书使用 x509 包。
我注册用户的代码如下:
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!";
我用来检查存储在密码中的属性的代码是:
//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
}
我用来更新证书属性的代码是:
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();
}
我想知道为什么证书还是旧密码,以及如何更新证书中的密码。 而且我还想知道 identityService 是否更新了 x509 证书中的属性,或者是否正在为此重新注册必要的用户?
你可以按照你说的reenroll
来修复它。
IdentityService
的update
命令是更新CA中registered
用户的身份。
由于这不是更新证书的过程,因此获得包含新修改的Attr
的证书的唯一方法是获得新证书(证书是X. 509 标准)。
为什么 attr 更改需要新证书?
- Fabric一般采用X.509证书标准方式。(不使用idemix时)
- 其实不只是Fabric,网上几乎所有的证书都遵循这个标准
- 在 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"}}
...
- 也就是说,修改
Attr
时,修改extensions
。 - 在 X.509(v3) 中,
extenstions
也包含在证书完整性验证过程中。 - 完整性验证过程是基于
PKI
和Hash
实现的,以在散列数据(包括扩展)中附加CA签名的signature
的形式提供) 到证书。 - 即修改了
extensions
,则必须修改证书中的signature
,即需要颁发新的证书。
回到 Fabric,
reenroll
命令是newly issuing
根据registered user
注册用户数据的行为。updating
后,通过reenroll
命令颁发新证书,获取相应证书中包含new Attrs
的证书
以下示例代码已经过测试并且可以运行。看到这个。
// 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
颁发证书的docode结果
(hf.Affiliation
和 userType
已更新)
// 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"}}
[P.S]看client's identity中的Version
,好像有办法升级现有的,不过我没查过也没试过