Topics

Supplying custom CSR with EnrolmentRequest in node-sdk fails #fabric #fabricca #fabric-sdk-node #fabric-ca

Mrudav Shukla
 

I have a single-org setup running with one Fabric CA. CA Server is running with MySQL. I'm using NodeSDK to connect and issue transactions to chaincode.

I'm able to set Country, State, Locality, Organisation and Organisation Unit attributes for the peers and orderers. However, when I register and enroll "users" with the Fabric, not all attributes are being set. Only the Common Name and Organisation Unit attributes are set as seen from the certificate file.

Following is my snippet for registering and enrolling users:

await gateway.connect(connectionProfile, { wallet, identity: 'admin', discovery: { enabled: false } });

ca = await gateway.getClient().getCertificateAuthority();
adminIdentity = gateway.getCurrentIdentity();

const secret = await ca.register({
                affiliation: user.$affiliation,
                enrollmentID: user.$name,
                role: user.$role,
               }, adminIdentity);

const enrollment = await ca.enroll({
                    enrollmentID: user.$name,
                    enrollmentSecret: secret,
                 });
const userIdentity = await X509WalletMixin.createIdentity(process.env.ACTIVE_MSP, enrollment.certificate, enrollment.key.toBytes());

Here, "user" is a model for a participant that I'm using in my application. The Common Name (CN) is set to "enrollmentID" and Organisation Unit is set to "role" + "affiliation" and the resultant certificate for the user has the following information:

Owner: CN=jondoe, OU=client + OU=admin.forwarder.com
Issuer: CN=ca.allparticipants.logistics.com, 
O=allparticipants.logistics.com, L=Bengaluru, ST=Karnataka, C=IN
Serial number: ea385863390c07c320fd6717de7878fd9f81dc3e
Valid from: Mon Apr 15 14:11:00 IST 2019 until: Tue Apr 14 14:16:00 IST 2020
Certificate fingerprints:
     MD5:  …<value>
     SHA1: …<value>
     SHA256: …<value>
Signature algorithm name: SHA256withECDSA
Subject Public Key Algorithm: 256-bit EC key
Version: 3

Extensions: 
…

As we can see, complete C, ST, L, O, OU and CN attributes of the Issuer is available. This belongs to MSP of the respective Org. However, only CN and OU of the user is available.

So is there a way with which we can set other attributes of the user (C, ST, L and O) while registering or enrolling user. Or do we have to infer these attributes from the issuer information?

Update: 1: I checked the fabric-ca-client cli options which the node-sdk calls internally. Checked the register api. It does not give an option to set C, ST, L, and O either.

Updates: Does fabric-ca support setting these attributes to the Subject Name?

Update: 2: Going through the documentation of fabric-ca-client and as suggested by @nyet, I observed that we can set these values in csr.names attribute and supply it to 'csr' argument of the enroll command. The updated code snippet below:

await gateway.connect(connectionProfile, { wallet, identity: 'admin', discovery: { enabled: false } });

ca = await gateway.getClient().getCertificateAuthority();

adminIdentity = gateway.getCurrentIdentity();

const secret = await ca.register({
            affiliation: user.$affiliation,
            enrollmentID: user.$name,
            role: user.$role,
           }, adminIdentity);

const csrObj: any = {};
csrObj.names = 'O=Forwarder,C=IN,ST=Karnataka,L=Bengaluru';

const enrollment = await ca.enroll({
            csr: csrObj.toString(),
            enrollmentID: user.$name,
            enrollmentSecret: secret,
            });

const userIdentity = await X509WalletMixin.createIdentity(process.env.ACTIVE_MSP, enrollment.certificate, enrollment.key.toBytes());

However, I get an error with this that says:

Failed to enroll smithdoe20, error:%o message=Enrollment failed with errors [[{"code":0,"message":"{\"code\":9002,\" message\":\"CSR Decode failed\"}"}]], stack=Error: Enrollment failed with errors [[{"code":0,"message":"{\"code\":9002,\"message\":\"CSR Decode failed\"}"}]]

Similar JIRA issue: https://jira.hyperledger.org/browse/FAB-14051?jql=project%20%3D%20FAB%20AND%20statusCategory%20!%3D%20Done%20AND%20type%20%3D%20Bug%20AND%20component%20%3D%20fabric-sdk-node%20AND%20project%20%3D%20FAB%20ORDER%20BY%20createdDate%20ASC

Update: 3: The Node-SDK documentation states that the CSR field should be a PEM-encoded PKCS#10 certificate signing request.

  1. I tried utilizing node-forge npm module to generate keys and sign proposal using it. However, that gives RSA keys.
  2. Tried using node-pem. Didn't work out either.

Finally, tried generating the ECDSA keys and created a CSR offline using the following commands: 1. Keys generation: openssl ecparam -name prime256v1 -genkey -noout -out my-key.pem 2. CSR: openssl req -new -sha256 -key my-key.pem -out my.csr

Read this CSR from the file system and passed it to Enrolment Request as follows:

 const csrNewVal = readFileSync('/Users/mrudavshukla/projects/pem-trials/ecdsa/my.csr', 'utf8');
 const enrollment = await ca.enroll({
                    csr: csrNewVal,
                    enrollmentID: user.$name,
                    enrollmentSecret: secret,
                });

Was able to enroll the user successfully.

Now, when we're passing the CSR, fabric-ca does not return us the enrolment key back. Thus, I retrieved the private key from #1 command from the file system and tried saving this user's identity details in X509 wallet as follows:

const privateNewVal = readFileSync('/Users/mrudavshukla/projects/pem-trials/ecdsa/my-key.pem', 'utf8');
const userIdentity = await X509WalletMixin.createIdentity(process.env.ACTIVE_MSP, enrollment.certificate, privateNewVal);

However, this throws the following error:

error: [crypto_ecdsa_aes]: importKey - {"message":"Does not understand PEM contents other than ECDSA private keys and certificates","stack":"Error: Does not understand PEM contents other than ECDSA private keys and certificates....

Next, I tried checking the certificate that was saved for this user with the one that fabric-ca generates when we do not supply CSR. Both are quite identical in structure and the signature algorithms used for the public key.

Am I missing out on any critical portion?