Skip to content

Commit

Permalink
[FAB-10681] Generate self-signed X509 cert
Browse files Browse the repository at this point in the history
Add a function to the ECDSA key class to generate
a self-signed X509 certificate.

Change-Id: I40a61a929a474c1caab3bcacd694443e6bec9a5f
Signed-off-by: Gari Singh <[email protected]>
  • Loading branch information
mastersingh24 committed Jun 20, 2018
1 parent 8935a0b commit 29fbf11
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 6 deletions.
63 changes: 59 additions & 4 deletions fabric-client/lib/impl/ecdsa/key.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const jsrsa = require('jsrsasign');
const asn1 = jsrsa.asn1;
const KEYUTIL = jsrsa.KEYUTIL;
const ECDSA = jsrsa.ECDSA;
const jws = jsrsa.jws;
const api = require('../../api');
const logger = utils.getLogger('ecdsa/key.js');

Expand All @@ -21,7 +22,7 @@ const logger = utils.getLogger('ecdsa/key.js');
* @class ECDSA_KEY
* @extends module:api.Key
*/
module.exports = class ECDSA_KEY extends api.Key{
module.exports = class ECDSA_KEY extends api.Key {
/**
* this class represents the private or public key of an ECDSA key pair.
*
Expand Down Expand Up @@ -53,7 +54,7 @@ module.exports = class ECDSA_KEY extends api.Key{
getSKI() {
let buff;

const pointToOctet = function(key) {
const pointToOctet = function (key) {
const byteLen = (key.ecparams.keylen + 7) >> 3;
const buff = Buffer.allocUnsafe(1 + 2 * byteLen);
buff[0] = 4; // uncompressed point (https://www.security-audit.com/files/x9-62-09-20-98.pdf, section 4.3.6)
Expand Down Expand Up @@ -111,13 +112,13 @@ module.exports = class ECDSA_KEY extends api.Key{
generateCSR(subjectDN) {

//check to see if this is a private key
if (!this.isPrivate()){
if (!this.isPrivate()) {
throw new Error('A CSR cannot be generated from a public key');
}

try {
const csr = asn1.csr.CSRUtil.newCSRPEM({
subject: { str: asn1.x509.X500Name.ldapToOneline(subjectDN)},
subject: { str: asn1.x509.X500Name.ldapToOneline(subjectDN) },
sbjpubkey: this.getPublicKey()._key,
sigalg: 'SHA256withECDSA',
sbjprvkey: this._key
Expand All @@ -128,6 +129,60 @@ module.exports = class ECDSA_KEY extends api.Key{
}
}

/**
* Generates a self-signed X.509 certificate
* @param {string} [commonName] The common name to use as the subject for the X509 certificate
* @returns {string} PEM-encoded X.509 certificate
* @throws Will throw an error if this is not a private key
* @throws Will throw an error if X.509 certificate generation fails for any other reason
*/
generateX509Certificate(commonName) {

var subjectDN = '/CN=self';
if (commonName) {
subjectDN = '/CN=' + commonName;
}
//check to see if this is a private key
if (!this.isPrivate()) {
throw new Error('An X509 certificate cannot be generated from a public key');
}

try {
var before = Date.now() - 60000;
var after = Date.now() + 60000;
var certPEM = asn1.x509.X509Util.newCertPEM({
serial: { int: 4 },
sigalg: { name: 'SHA256withECDSA' },
issuer: { str: subjectDN },
notbefore: { 'str': jws.IntDate.intDate2Zulu(jws.IntDate.getNow() - 5000) },
notafter: { 'str': jws.IntDate.intDate2Zulu(jws.IntDate.getNow() + 60000) },
subject: { str: subjectDN },
sbjpubkey: this.getPublicKey()._key,
ext: [
{
basicConstraints: {
cA: false,
critical: true
}
},
{
keyUsage: { bin: '11'}
},
{
extKeyUsage: {
array: [{name: 'clientAuth'}]
}
}
],
cakey: this._key
});
return certPEM;

} catch (err) {
throw err;
}
}

toBytes() {
// this is specific to the private key format generated by
// npm module 'jsrsasign.KEYUTIL'
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions test/unit/ecdsa-key.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var ecdsaKey = require('fabric-client/lib/impl/ecdsa/key.js');
var jsrsa = require('jsrsasign');
var KEYUTIL = jsrsa.KEYUTIL;
var asn1 = jsrsa.asn1;
var X509 = require('x509');

test('\n\n ** ECDSA Key Impl tests **\n\n', function (t) {
testutil.resetDefaults();
Expand Down Expand Up @@ -150,5 +151,34 @@ test('\n\n ** ECDSA Key Impl tests **\n\n', function (t) {
t.equal(csrObject.pubkey.obj.pubKeyHex, key3.getPublicKey()._key.pubKeyHex,
'Checking CSR public key matches requested public key');

//test X509 generation
var x509PEM;
var cert;
try {
x509PEM = key3.generateX509Certificate();
cert = X509.parseCert(x509PEM);
console.log(JSON.stringify(cert,'',2));
t.equal(cert.subject.commonName,'self', 'Checking common name set to default');
} catch (err) {
t.fail('Failed to generate an X509 Certificate: ' + err.stack ? err.stack : err);
}

try {
x509PEM = key3.generateX509Certificate('testUser');
cert = X509.parseCert(x509PEM);
console.log(JSON.stringify(cert,'',2));
t.equal(cert.subject.commonName,'testUser', 'Checking common name set to "testUser"');
} catch (err) {
t.fail('Failed to generate an X509 Certificate: ' + err.stack ? err.stack : err);
}

t.throws(
function () {
key3.getPublicKey().generateX509Certificate();
},
/An X509 certificate cannot be generated from a public key/,
'Checking that an X509 cannot be generated from a public key'
);

t.end();
});

0 comments on commit 29fbf11

Please sign in to comment.