Skip to content

Commit af3f229

Browse files
author
Frank Schmid
committed
Support EC private key PEM export
1 parent b110210 commit af3f229

3 files changed

Lines changed: 45 additions & 31 deletions

File tree

lib/keytypes/ECKey.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const ECPublicKeyHeader = asn.define('ECPublicKeyHeader', function() {
2727
this.key('keyType').objid({
2828
'1.2.840.10045.2.1': 'EC'
2929
}),
30-
this.key('curve').objid(CURVE_OIDS)
30+
this.key('crv').objid(CURVE_OIDS)
3131
);
3232
});
3333

@@ -38,6 +38,15 @@ const ECPublicKey = asn.define('ECPublicKey', function() {
3838
);
3939
});
4040

41+
const ECPrivateKey = asn.define('ECPrivateKey', function() {
42+
this.seq().obj(
43+
this.key('id').int(),
44+
this.key('d').octstr(),
45+
this.key('crv').explicit(0).objid(CURVE_OIDS),
46+
this.key('coord').explicit(1).bitstr()
47+
);
48+
});
49+
4150
class ECKey {
4251

4352
constructor(crv, x, y, d) {
@@ -58,7 +67,7 @@ class ECKey {
5867
const params = {
5968
header: {
6069
keyType: 'EC',
61-
curve: this._crv
70+
crv: this._crv
6271
},
6372
content: {
6473
data: coordinate
@@ -67,6 +76,23 @@ class ECKey {
6776
return ECPublicKey.encode(params, 'pem', { label: 'PUBLIC KEY' });
6877
}
6978

79+
toPrivateKeyPEM() {
80+
if (!this.hasPrivateKey) {
81+
return null;
82+
}
83+
84+
// Construct x/y coordinate
85+
const coordinate = Buffer.concat([COORD_PREFIX_UNCOMPRESSED, this._x, this._y]);
86+
87+
const params = {
88+
id: 1,
89+
d: this._d,
90+
crv: this._crv,
91+
coord: { data: coordinate }
92+
};
93+
return ECPrivateKey.encode(params, 'pem', { label: 'EC PRIVATE KEY' });
94+
}
95+
7096
static validate(key) {
7197
// y must only be defined for the three curves defined in RFC-7517 par. 6.2.1
7298
// FIXME: Currently y is treated as mandatory here.

lib/util.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,3 @@ function unsigned(bignum) {
1919
}
2020

2121
module.exports.unsigned = unsigned;
22-
module.exports.zeroBuffer = zeroBuffer;

test/tests/ec.test.js

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@ describe('EC key', () => {
1010
it('should be initialized from public key objects', () => {
1111

1212
const keySet = JWKSet.fromObject(publicKS);
13-
const jwk = keySet.findKeyById('2011-04-29');
13+
const jwk = keySet.findKeyById('k1');
1414

15-
expect(keySet.keys).to.satisfy(k => /(?!.*_invalid)$/.test(k.kid));
15+
expect(jwk.kid).to.be.equal('k1');
16+
expect(jwk.key.hasPrivateKey).to.be.false;
17+
18+
const pubKey = jwk.key.toPublicKeyPEM();
19+
expect(pubKey).to.be.equal(`-----BEGIN PUBLIC KEY-----
20+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ41kktcqHeQYVdFMlv6AorbqOlmQ
21+
ESJqR4ZKiozpw0Lte4nZ4bm5uzeImkKvHADS+iBxSoBJGXyR7OOkh8dFvg==
22+
-----END PUBLIC KEY-----`);
1623

1724
});
1825

@@ -25,35 +32,17 @@ describe('EC key', () => {
2532
expect(jwk.key.hasPrivateKey).to.be.true;
2633

2734
const pubKey = jwk.key.toPublicKeyPEM();
28-
console.log(pubKey);
29-
exit();
3035
expect(pubKey).to.be.equal(`-----BEGIN PUBLIC KEY-----
31-
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0vx7agoebGcQSuuPiLJX
32-
ZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tS
33-
oc/BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ/2W+5JsGY4Hc5n9yBXArwl93lqt
34-
7/RN5w6Cf0h4QyQ5v+65YGjQR0/FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0
35-
zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt+bFTWhAI4vMQFh6WeZu0f
36-
M4lFd2NcRwr3XPksINHaQ+G/xBniIqbw0Ls1jF44+csFCur+kEgU8awapJzKnqDK
37-
gwIDAQAB
36+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A
37+
iTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==
3838
-----END PUBLIC KEY-----`);
3939

40-
});
41-
42-
it('should be initialized from private key objects', () => {
43-
44-
const keySet = JWKSet.fromObject(privateKS);
45-
const jwk = keySet.findKeyById('2011-04-29');
46-
47-
const pubKey = jwk.key.toPublicKeyPEM();
48-
expect(pubKey).to.be.equal(`-----BEGIN PUBLIC KEY-----
49-
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0vx7agoebGcQSuuPiLJX
50-
ZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tS
51-
oc/BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ/2W+5JsGY4Hc5n9yBXArwl93lqt
52-
7/RN5w6Cf0h4QyQ5v+65YGjQR0/FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0
53-
zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt+bFTWhAI4vMQFh6WeZu0f
54-
M4lFd2NcRwr3XPksINHaQ+G/xBniIqbw0Ls1jF44+csFCur+kEgU8awapJzKnqDK
55-
gwIDAQAB
56-
-----END PUBLIC KEY-----`);
40+
const privKey = jwk.key.toPrivateKeyPEM();
41+
expect(privKey).to.be.equal(`-----BEGIN EC PRIVATE KEY-----
42+
MHcCAQEEIPO9DAeoH7kyeB7VJ1L2DMiaa+XlGTT+AZON21XY93gBoAoGCCqGSM49
43+
AwEHoUQDQgAEMKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D7gS2XpJFbZ
44+
iItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==
45+
-----END EC PRIVATE KEY-----`);
5746

5847
});
5948

0 commit comments

Comments
 (0)