title: Hyperledger Fabric Node.js SDK: Issue with offline transaction signatures
body: <p>I am trying to follow this tutorial:
  <a href="https://hyperledger.github.io/fabric-sdk-node/release-1.4/tutorial-sign-transaction-offline.html" rel="nofollow noreferrer">https://hyperledger.github.io/fabric-sdk-node/release-1.4/tutorial-sign-transaction-offline.html</a></p>
  
  <p>I created a complete Hyperledger Fabric network using this guide:
  <a href="https://hyperledger-fabric-ca.readthedocs.io/en/latest/operations_guide.html" rel="nofollow noreferrer">https://hyperledger-fabric-ca.readthedocs.io/en/latest/operations_guide.html</a></p>
  
  <p>The Javascript SDK is working well, and I can query/invoke transactions using the client.setUserContext() method.</p>
  
  <p>When trying to sign the transaction offline, the transaction proposal is rejected by the peers with the following response:</p>
  
  <pre><code>{ Error: 2 UNKNOWN: access denied: channel [mychannel] creator org [org1]
        at Object.exports.createStatusError ([...]/node_modules/grpc/src/common.js:91:15)
        at Object.onReceiveStatus ([...]/node_modules/grpc/src/client_interceptors.js:1204:28)
        at InterceptingListener._callNext ([...]/node/node_modules/grpc/src/client_interceptors.js:568:42)
        at InterceptingListener.onReceiveStatus ([...]/node/node_modules/grpc/src/client_interceptors.js:618:8)
        at callback ([...]/node/node_modules/grpc/src/client_interceptors.js:845:24)
      code: 2,
      metadata: Metadata { _internal_repr: {} },
      details: 'access denied: channel [mychannel] creator org [org1]' }
  </code></pre>
  
  <p>In the logs from the peers, I see the following error:</p>
  
  <pre><code>peer1-org1       | 2020-01-13 21:47:31.569 UTC [protoutils] ValidateProposalMessage -&gt; WARN 078 channel [mychannel]: creator's signature over the proposal is not valid: The signature is invalid
  </code></pre>
  
  <p>I do not understand why the signature is rejected. I carefully followed all the steps of the tutorial. Here is the complete client code:</p>
  
  <pre><code>//
  // Imports
  //
  var Client = require('fabric-client');
  var path = require('path');
  var util = require('util');
  var fs = require('fs');
  const crypto = require('crypto');
  const elliptic = require('elliptic');
  const { KEYUTIL } = require('jsrsasign');
  const config = require('./config');
  
  //
  // Script configuartion variables
  //
  var fcn = 'set';
  var args = ["a","60"];
  var priv = fs.readFileSync(config.PRIV, 'utf8');
  var { prvKeyHex } = KEYUTIL.getKey(priv,'passphrase'); 
  var cert = fs.readFileSync(config.CERT, 'utf8');
  const EC = elliptic.ec;
  const ecdsaCurve = elliptic.curves['p256'];
  const ecdsa = new EC(ecdsaCurve);
  const signKey = ecdsa.keyFromPrivate(prvKeyHex, 'hex');
  
  
  //
  // Config init
  //
  var client = Client.loadFromConfig('network_org1.yaml');
  var targets = client.getPeersForOrg('org1');
  
  // 
  // Main
  // 
  client.initCredentialStores()
  .then((nothing) =&gt; {
  
  channel = client.getChannel(config.CHANNEL_NAME);
  
  // 1. Generate unsigned transaction proposal
  var transaction_proposal = {
    chaincodeId: config.CHAINCODE_NAME,
    channelId: config.CHANNEL_NAME,
    fcn: fcn,
    args: args,
  };
  
  var { proposal, tx_id } = channel.generateUnsignedProposal(transaction_proposal, 'org1', cert);
  
  // 2. Hash the transaction proposal
  var proposalBytes = proposal.toBuffer();
  var digest = client.getCryptoSuite().hash(proposalBytes);
  //const hash = crypto.createHash('sha256');
  //hash.update(proposalBytes);
  //var digest = hash.digest('hex');
  
  // 3. Calculate the signature for this transacton proposal
  console.log("digest: "+digest);   
  console.log("signKey: ");
  console.log(util.inspect(signKey));
  var sig = ecdsa.sign(Buffer.from(digest, 'hex'), signKey);
  var signature = Buffer.from(sig.toDER());
  var signedProposal = {
    signature,
    proposal_bytes: proposalBytes,
  };
  
  // 4. Send the signed transaction proposal
  var proposal_request = {
    signedProposal,
    targets
  }
  channel.sendSignedProposal(proposal_request)
  .then((proposalResponses) =&gt; {
      console.log('Proposal responses:');
      console.log(util.inspect(proposalResponses));
  
      // TODO: Understand why the proposal signature is rejected by the peers
  
      // 5. Generate unsigned transaction
      var transaction_request = {
        proposalResponses,
        proposal,
      };
      return channel.generateUnsignedTransaction(transaction_request);
  })  
  .then((commitProposal) =&gt; {
  
      // 6. Sign the unsigned transaction
      var transactionBytes = commitProposal.toBuffer();
      var transaction_digest = client.getCryptoSuite().hash(transactionBytes);
      var transaction_sig = ecdsa.sign(Buffer.from(transaction_digest, 'hex'), signKey);        
      var transaction_signature = Buffer.from(transaction_sig.toDER());
  
      var signedTransaction = {
        signedProposal: transaction_signature,
        request: transaction_request
      }
  
      // 7. Commit the signed transaction
      return channel.sendSignedTransaction(signedTransaction);
  })
  .then((response) =&gt; {
      console.log('Successfully sent transaction');
      console.log('Return code: '+response.status);
  });
  
  });
  </code></pre>
  
  <p>Any help from anybody who might have successfully signed transactions offline would be fantastic. </p>