From 31576819fdb7e9989f312d2d1c2833568f8c9ae1 Mon Sep 17 00:00:00 2001
From: Salman Baset <sabaset@us.ibm.com>
Date: Sat, 11 Aug 2018 15:08:46 -0400
Subject: [PATCH] added support for secp256r1 curve. modified the tests to
 accept multiple curves.

---
 README.md          |   2 +-
 lib/key-encoder.js |   7 ++
 package.json       |   2 +-
 test.js            | 203 +++++++++++++++++++++++++++------------------
 4 files changed, 131 insertions(+), 83 deletions(-)

diff --git a/README.md b/README.md
index 54cacf3..5ca0dcc 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ $ npm install key-encoder
 
 ### Getting Started
 
-To get started, first define your key encoder and raw private/public keys.
+To get started, first define your key encoder and raw private/public keys. Keyencoder supports the following curves: `secp256k1`, `secp256r1`
 
 #### SECP256k1 Key Encoders
 
diff --git a/lib/key-encoder.js b/lib/key-encoder.js
index 286e522..f83c203 100644
--- a/lib/key-encoder.js
+++ b/lib/key-encoder.js
@@ -29,6 +29,13 @@ var curves = {
         privatePEMOptions: {label: 'EC PRIVATE KEY'},
         publicPEMOptions: {label: 'PUBLIC KEY'},
         curve: new EC('secp256k1')
+    },
+    //prime256v1/secp256r1: parameters from RFC 5480, Section 2.1.1.1
+    secp256r1: {
+        curveParameters: [1, 2, 840, 10045, 3, 1, 7],
+        privatePEMOptions: {label: 'EC PRIVATE KEY'},
+        publicPEMOptions: {label: 'PUBLIC KEY'},
+        curve: new EC('p256')
     }
 }
 
diff --git a/package.json b/package.json
index 27f7665..25323c0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "key-encoder",
-  "version": "1.1.6",
+  "version": "1.1.7",
   "description": "Library for encoding ECDSA private keys to PEM, DER and raw hex formats",
   "main": "index.js",
   "scripts": {
diff --git a/test.js b/test.js
index 492df4c..6e39943 100644
--- a/test.js
+++ b/test.js
@@ -4,127 +4,168 @@ var test = require('tape'),
     SubjectPublicKeyInfoASN = KeyEncoder.SubjectPublicKeyInfoASN,
     BN = require('bn.js')
 
-var keys = {
-    rawPrivate: '844055cca13efd78ce79a4c3a4c5aba5db0ebeb7ae9d56906c03d333c5668d5b',
-    rawPublic: '04147b79e9e1dd3324ceea115ff4037b6c877c73777131418bfb2b713effd0f502327b923861581bd5535eeae006765269f404f5f5c52214e9721b04aa7d040a75',
-    pemPrivate: '-----BEGIN EC PRIVATE KEY-----\n' +
-    'MHQCAQEEIIRAVcyhPv14znmkw6TFq6XbDr63rp1WkGwD0zPFZo1boAcGBSuBBAAK\n' +
-    'oUQDQgAEFHt56eHdMyTO6hFf9AN7bId8c3dxMUGL+ytxPv/Q9QIye5I4YVgb1VNe\n' +
-    '6uAGdlJp9AT19cUiFOlyGwSqfQQKdQ==\n' +
-    '-----END EC PRIVATE KEY-----',
-    pemCompactPrivate: '-----BEGIN EC PRIVATE KEY-----\n' +
-    'MC4CAQEEIIRAVcyhPv14znmkw6TFq6XbDr63rp1WkGwD0zPFZo1boAcGBSuBBAAK\n' +
-    '-----END EC PRIVATE KEY-----',
-    pemPublic: '-----BEGIN PUBLIC KEY-----\n' +
-    'MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEFHt56eHdMyTO6hFf9AN7bId8c3dxMUGL\n' +
-    '+ytxPv/Q9QIye5I4YVgb1VNe6uAGdlJp9AT19cUiFOlyGwSqfQQKdQ==\n' +
-    '-----END PUBLIC KEY-----',
-    derPrivate: '30740201010420844055cca13efd78ce79a4c3a4c5aba5db0ebeb7ae9d56906c03d333c5668d5ba00706052b8104000aa14403420004147b79e9e1dd3324ceea115ff4037b6c877c73777131418bfb2b713effd0f502327b923861581bd5535eeae006765269f404f5f5c52214e9721b04aa7d040a75',
-    derPublic: '3056301006072a8648ce3d020106052b8104000a03420004147b79e9e1dd3324ceea115ff4037b6c877c73777131418bfb2b713effd0f502327b923861581bd5535eeae006765269f404f5f5c52214e9721b04aa7d040a75'
-}
-
-var keyEncoder = new KeyEncoder('secp256k1')
+var keys = [
+    //secp256k1
+    {
+        rawPrivate: '844055cca13efd78ce79a4c3a4c5aba5db0ebeb7ae9d56906c03d333c5668d5b',
+        rawPublic: '04147b79e9e1dd3324ceea115ff4037b6c877c73777131418bfb2b713effd0f502327b923861581bd5535eeae006765269f404f5f5c52214e9721b04aa7d040a75',
+        pemPrivate: '-----BEGIN EC PRIVATE KEY-----\n' +
+        'MHQCAQEEIIRAVcyhPv14znmkw6TFq6XbDr63rp1WkGwD0zPFZo1boAcGBSuBBAAK\n' +
+        'oUQDQgAEFHt56eHdMyTO6hFf9AN7bId8c3dxMUGL+ytxPv/Q9QIye5I4YVgb1VNe\n' +
+        '6uAGdlJp9AT19cUiFOlyGwSqfQQKdQ==\n' +
+        '-----END EC PRIVATE KEY-----',
+        pemCompactPrivate: '-----BEGIN EC PRIVATE KEY-----\n' +
+        'MC4CAQEEIIRAVcyhPv14znmkw6TFq6XbDr63rp1WkGwD0zPFZo1boAcGBSuBBAAK\n' +
+        '-----END EC PRIVATE KEY-----',
+        pemPublic: '-----BEGIN PUBLIC KEY-----\n' +
+        'MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEFHt56eHdMyTO6hFf9AN7bId8c3dxMUGL\n' +
+        '+ytxPv/Q9QIye5I4YVgb1VNe6uAGdlJp9AT19cUiFOlyGwSqfQQKdQ==\n' +
+        '-----END PUBLIC KEY-----',
+        derPrivate: '30740201010420844055cca13efd78ce79a4c3a4c5aba5db0ebeb7ae9d56906c03d333c5668d5ba00706052b8104000aa14403420004147b79e9e1dd3324ceea115ff4037b6c877c73777131418bfb2b713effd0f502327b923861581bd5535eeae006765269f404f5f5c52214e9721b04aa7d040a75',
+        derPublic: '3056301006072a8648ce3d020106052b8104000a03420004147b79e9e1dd3324ceea115ff4037b6c877c73777131418bfb2b713effd0f502327b923861581bd5535eeae006765269f404f5f5c52214e9721b04aa7d040a75'
+    },
+    //secp256r1
+    {
+        rawPrivate: 'ff2d3419e5d1e9421ba3ad0c398369ca7c09de3ad5c163e1ce370d0df8f2f9d8',
+        rawPublic: '0478b62fda69d898dfedadb897d6a8a7f0d1a9687eb8cee28b9db05a9d094ad92da36202d8499b0635b38fff3a99eaacdc7e2990807c72d8256b49f853b739872d',
+        pemPrivate: '-----BEGIN EC PRIVATE KEY-----\n' +
+        'MHcCAQEEIP8tNBnl0elCG6OtDDmDacp8Cd461cFj4c43DQ348vnYoAoGCCqGSM49\n' +
+        'AwEHoUQDQgAEeLYv2mnYmN/trbiX1qin8NGpaH64zuKLnbBanQlK2S2jYgLYSZsG\n' +
+        'NbOP/zqZ6qzcfimQgHxy2CVrSfhTtzmHLQ==\n' +
+        '-----END EC PRIVATE KEY-----',
+        pemPublic: '-----BEGIN PUBLIC KEY-----\n' +
+        'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeLYv2mnYmN/trbiX1qin8NGpaH64\n' +
+        'zuKLnbBanQlK2S2jYgLYSZsGNbOP/zqZ6qzcfimQgHxy2CVrSfhTtzmHLQ==\n' +
+        '-----END PUBLIC KEY-----',
+        derPrivate: '30770201010420ff2d3419e5d1e9421ba3ad0c398369ca7c09de3ad5c163e1ce370d0df8f2f9d8a00a06082a8648ce3d030107a1440342000478b62fda69d898dfedadb897d6a8a7f0d1a9687eb8cee28b9db05a9d094ad92da36202d8499b0635b38fff3a99eaacdc7e2990807c72d8256b49f853b739872d',
+        derPublic: '3059301306072a8648ce3d020106082a8648ce3d0301070342000478b62fda69d898dfedadb897d6a8a7f0d1a9687eb8cee28b9db05a9d094ad92da36202d8499b0635b38fff3a99eaacdc7e2990807c72d8256b49f853b739872d'
+    }
+]
+
+var curve_params = [
+    [1, 3, 132, 0, 10], //secp256k1
+    [1, 2, 840, 10045, 3, 1, 7], //secp256r1
+]
+
+var keyEncoder = [];
+keyEncoder[0] = new KeyEncoder('secp256k1')
+keyEncoder[1] = new KeyEncoder('secp256r1')
 
 test('encodeECPrivateKeyASN', function(t) {
-    t.plan(3)
+    t.plan(3*keys.length)
 
-    var secp256k1Parameters = [1, 3, 132, 0, 10],
-        pemOptions =  {label: 'EC PRIVATE KEY'}
+    var pemOptions =  {label: 'EC PRIVATE KEY'}
 
-    var privateKeyObject = {
-        version: new BN(1),
-        privateKey: new Buffer(keys.rawPrivate, 'hex'),
-        parameters: secp256k1Parameters,
-        publicKey: { unused: 0, data: new Buffer(keys.rawPublic, 'hex') }
-    }
+    for (let i=0; i < keys.length; i++) {
+        var privateKeyObject = {
+            version: new BN(1),
+            privateKey: new Buffer(keys[i].rawPrivate, 'hex'),
+            parameters: curve_params[i],
+            publicKey: { unused: 0, data: new Buffer(keys[i].rawPublic, 'hex') }
+        }
 
-    var privateKeyPEM = ECPrivateKeyASN.encode(privateKeyObject, 'pem', pemOptions)
-    t.equal(privateKeyPEM, keys.pemPrivate, 'encoded PEM private key should match the OpenSSL reference')
+        var privateKeyPEM = ECPrivateKeyASN.encode(privateKeyObject, 'pem', pemOptions)
+        t.equal(privateKeyPEM, keys[i].pemPrivate, 'encoded PEM private key should match the OpenSSL reference')
 
-    var decodedPrivateKeyObject = ECPrivateKeyASN.decode(privateKeyPEM, 'pem', pemOptions)
-    t.equal(JSON.stringify(privateKeyObject), JSON.stringify(decodedPrivateKeyObject), 'encoded-and-decoded private key object should match the original')
+        var decodedPrivateKeyObject = ECPrivateKeyASN.decode(privateKeyPEM, 'pem', pemOptions)
+        t.equal(JSON.stringify(privateKeyObject), JSON.stringify(decodedPrivateKeyObject), 'encoded-and-decoded private key object should match the original')
 
-    var openSSLPrivateKeyObject = ECPrivateKeyASN.decode(keys.pemPrivate, 'pem', pemOptions)
-    t.equal(JSON.stringify(privateKeyObject), JSON.stringify(openSSLPrivateKeyObject), 'private key object should match the one decoded from the OpenSSL PEM')
+        var openSSLPrivateKeyObject = ECPrivateKeyASN.decode(keys[i].pemPrivate, 'pem', pemOptions)
+        t.equal(JSON.stringify(privateKeyObject), JSON.stringify(openSSLPrivateKeyObject), 'private key object should match the one decoded from the OpenSSL PEM')
+    }
 })
 
 test('encodeSubjectPublicKeyInfoASN', function(t) {
-    t.plan(1)
-
-    var secp256k1Parameters = [1, 3, 132, 0, 10],
-        pemOptions =  {label: 'PUBLIC KEY'}
-
-    var publicKeyObject = {
-        algorithm: {
-            id: [1, 2, 840, 10045, 2, 1],
-            curve: secp256k1Parameters
-        },
-        pub: {
-            unused: 0,
-            data: new Buffer(keys.rawPublic, 'hex')
+    t.plan(2)
+
+    var pemOptions =  {label: 'PUBLIC KEY'}
+
+    for (let i=0; i < keys.length; i++) {
+        var publicKeyObject = {
+            algorithm: {
+                id: [1, 2, 840, 10045, 2, 1],
+                curve: curve_params[i]
+            },
+            pub: {
+                unused: 0,
+                data: new Buffer(keys[i].rawPublic, 'hex')
+            }
         }
-    }
 
-    var publicKeyPEM = SubjectPublicKeyInfoASN.encode(publicKeyObject, 'pem', pemOptions)
-    t.equal(publicKeyPEM, keys.pemPublic, 'encoded PEM public key should match the OpenSSL reference')
+        var publicKeyPEM = SubjectPublicKeyInfoASN.encode(publicKeyObject, 'pem', pemOptions)
+        t.equal(publicKeyPEM, keys[i].pemPublic, 'encoded PEM public key should match the OpenSSL reference')
+    }
 })
 
 test('encodeRawPrivateKey', function(t) {
-    t.plan(2)
+    t.plan(4)
 
-    var privateKeyPEM = keyEncoder.encodePrivate(keys.rawPrivate, 'raw', 'pem')
-    t.equal(privateKeyPEM, keys.pemPrivate, 'encoded PEM private key should match the OpenSSL reference')
+    for (let i=0; i < keys.length; i++) {
+        var privateKeyPEM = keyEncoder[i].encodePrivate(keys[i].rawPrivate, 'raw', 'pem')
+        t.equal(privateKeyPEM, keys[i].pemPrivate, 'encoded PEM private key should match the OpenSSL reference')
 
-    var privateKeyDER = keyEncoder.encodePrivate(keys.rawPrivate, 'raw', 'der')
-    t.equal(privateKeyDER, keys.derPrivate, 'encoded DER private key should match the OpenSSL reference')
+        var privateKeyDER = keyEncoder[i].encodePrivate(keys[i].rawPrivate, 'raw', 'der')
+        console.log(privateKeyDER)
+        t.equal(privateKeyDER, keys[i].derPrivate, 'encoded DER private key should match the OpenSSL reference')
+    }
 })
 
 test('encodeDERPrivateKey', function(t) {
-    t.plan(2)
+    t.plan(4)
 
-    var rawPrivateKey = keyEncoder.encodePrivate(keys.derPrivate, 'der', 'raw')
-    t.equal(rawPrivateKey, keys.rawPrivate, 'encoded raw private key should match the OpenSSL reference')
+    for (let i=0; i < keys.length; i++) {
+        var rawPrivateKey = keyEncoder[i].encodePrivate(keys[i].derPrivate, 'der', 'raw')
+        t.equal(rawPrivateKey, keys[i].rawPrivate, 'encoded raw private key should match the OpenSSL reference')
 
-    var privateKeyPEM = keyEncoder.encodePrivate(keys.derPrivate, 'der', 'pem')
-    t.equal(privateKeyPEM, keys.pemPrivate, 'encoded PEM private key should match the OpenSSL reference')
+        var privateKeyPEM = keyEncoder[i].encodePrivate(keys[i].derPrivate, 'der', 'pem')
+        t.equal(privateKeyPEM, keys[i].pemPrivate, 'encoded PEM private key should match the OpenSSL reference')
+    }
 })
 
 test('encodePEMPrivateKey', function(t) {
-    t.plan(2)
+    t.plan(4)
 
-    var rawPrivateKey = keyEncoder.encodePrivate(keys.pemPrivate, 'pem', 'raw')
-    t.equal(rawPrivateKey, keys.rawPrivate, 'encoded raw private key should match the OpenSSL reference')
+    for (let i=0; i < keys.length; i++) {
+        var rawPrivateKey = keyEncoder[i].encodePrivate(keys[i].pemPrivate, 'pem', 'raw')
+        t.equal(rawPrivateKey, keys[i].rawPrivate, 'encoded raw private key should match the OpenSSL reference')
 
-    var privateKeyDER = keyEncoder.encodePrivate(keys.pemPrivate, 'pem', 'der')
-    t.equal(privateKeyDER, keys.derPrivate, 'encoded DER private key should match the OpenSSL reference')
+        var privateKeyDER = keyEncoder[i].encodePrivate(keys[i].pemPrivate, 'pem', 'der')
+        t.equal(privateKeyDER, keys[i].derPrivate, 'encoded DER private key should match the OpenSSL reference')
+    }
 })
 
 test('encodeRawPublicKey', function(t) {
-    t.plan(2)
+    t.plan(4)
 
-    var publicKeyPEM = keyEncoder.encodePublic(keys.rawPublic, 'raw', 'pem')
-    t.equal(publicKeyPEM, keys.pemPublic, 'encoded PEM public key should match the OpenSSL reference')
+    for (let i=0; i < keys.length; i++) {
+        var publicKeyPEM = keyEncoder[i].encodePublic(keys[i].rawPublic, 'raw', 'pem')
+        t.equal(publicKeyPEM, keys[i].pemPublic, 'encoded PEM public key should match the OpenSSL reference')
 
-    var publicKeyDER = keyEncoder.encodePublic(keys.rawPublic, 'raw', 'der')
-    t.equal(publicKeyDER, keys.derPublic, 'encoded DER public key should match the OpenSSL reference')
+        var publicKeyDER = keyEncoder[i].encodePublic(keys[i].rawPublic, 'raw', 'der')
+        t.equal(publicKeyDER, keys[i].derPublic, 'encoded DER public key should match the OpenSSL reference')
+    }
 })
 
 test('encodeDERPublicKey', function(t) {
-    t.plan(2)
+    t.plan(4)
 
-    var rawPublicKey = keyEncoder.encodePublic(keys.derPublic, 'der', 'raw')
-    t.equal(rawPublicKey, keys.rawPublic, 'encoded raw public key should match the OpenSSL reference')
+    for (let i=0; i < keys.length; i++) {
+        var rawPublicKey = keyEncoder[i].encodePublic(keys[i].derPublic, 'der', 'raw')
+        t.equal(rawPublicKey, keys[i].rawPublic, 'encoded raw public key should match the OpenSSL reference')
 
-    var publicKeyPEM = keyEncoder.encodePublic(keys.derPublic, 'der', 'pem')
-    t.equal(publicKeyPEM, keys.pemPublic, 'encoded PEM public key should match the OpenSSL reference')
+        var publicKeyPEM = keyEncoder[i].encodePublic(keys[i].derPublic, 'der', 'pem')
+        t.equal(publicKeyPEM, keys[i].pemPublic, 'encoded PEM public key should match the OpenSSL reference')
+    }
 })
 
 test('encodePEMPublicKey', function(t) {
-    t.plan(2)
+    t.plan(4)
 
-    var rawPublicKey = keyEncoder.encodePublic(keys.pemPublic, 'pem', 'raw')
-    t.equal(rawPublicKey, keys.rawPublic, 'encoded raw public key should match the OpenSSL reference')
+    for (let i=0; i < keys.length; i++) {
+        var rawPublicKey = keyEncoder[i].encodePublic(keys[i].pemPublic, 'pem', 'raw')
+        t.equal(rawPublicKey, keys[i].rawPublic, 'encoded raw public key should match the OpenSSL reference')
 
-    var publicKeyDER = keyEncoder.encodePublic(keys.pemPublic, 'pem', 'der')
-    t.equal(publicKeyDER, keys.derPublic, 'encoded DER public key should match the OpenSSL reference')
+        var publicKeyDER = keyEncoder[i].encodePublic(keys[i].pemPublic, 'pem', 'der')
+        t.equal(publicKeyDER, keys[i].derPublic, 'encoded DER public key should match the OpenSSL reference')
+    }
 })