@@ -7,43 +7,51 @@ const {
77 privateKeyToPem,
88 publicKeyFromPem,
99 privateKeyFromPem,
10+ setRsaPublicKey,
11+ createCertificate,
12+ certificateToPem,
13+ certificateFromPem,
14+ } ,
15+ md : {
16+ sha256,
1017 } ,
1118 jsbn : {
1219 BigInteger,
1320 } ,
1421} = require ( 'node-forge' ) ;
22+ const { X509Certificate } = require ( 'crypto' ) ;
1523
1624const getKeyType = ( str ) => {
17- const matches = str . match ( / ( P R I V A T E | P U B L I C ) K E Y / ) ;
25+ const matches = str . match ( / B E G I N (?: R S A ) ? ( P R I V A T E | P U B L I C | C E R T I F I C A T E ) / ) ;
1826 if ( ! matches )
1927 return null ;
2028 return matches [ 1 ] . toLowerCase ( ) ;
2129} ;
2230
23- const keyFromPem = ( pem ) => {
24- const type = getKeyType ( pem ) ;
25- const isPublic = type === 'public' ;
26- const key = isPublic ? publicKeyFromPem ( pem ) : privateKeyFromPem ( pem ) ;
27-
28- return {
29- isPublic ,
30- key ,
31- } ;
32- } ;
33-
34- /**
35- * Creates a public key from modulus and exponent
36- * @param { Buffer } mod - the modulus
37- * @param { Buffer } exp - the exponent
38- */
39- const keyFromModAndExp = ( mod , exp ) => {
40- const bnMod = new BigInteger ( mod . toString ( 'hex' ) , 16 ) ;
41- const bnExp = new BigInteger ( exp . toString ( 'hex' ) , 16 ) ;
42-
43- return {
44- key : rsa . setPublicKey ( bnMod , bnExp ) ,
45- isPublic : true ,
46- } ;
31+ const certificateFromPrivateKey = ( privateKey ) => {
32+ const certificate = createCertificate ( ) ;
33+ certificate . publicKey = setRsaPublicKey ( privateKey . n , privateKey . e ) ;
34+ certificate . validity . notBefore = new Date ( '2000-01-01' ) ;
35+ certificate . validity . notAfter = new Date ( '9999-12-31' ) ;
36+ certificate . setIssuer ( [
37+ {
38+ shortName : 'CN' , value : 'ebics.example.com' ,
39+ } ,
40+ ] ) ;
41+ certificate . subject = certificate . issuer ;
42+ certificate . setExtensions ( [
43+ {
44+ name : 'keyUsage' ,
45+ keyCertSign : true ,
46+ digitalSignature : true ,
47+ nonRepudiation : true ,
48+ keyEncipherment : true ,
49+ dataEncipherment : true ,
50+ } ,
51+ ] ) ;
52+ certificate . sign ( privateKey , sha256 . create ( ) ) ;
53+
54+ return certificate ;
4755} ;
4856
4957module . exports = class Key {
@@ -54,39 +62,68 @@ module.exports = class Key {
5462 if ( ! pem && ! mod && ! exp ) {
5563 const keyPair = rsa . generateKeyPair ( size ) ;
5664
57- this . keyIsPublic = false ;
65+ this . type = 'private' ;
5866 this . privateKey = keyPair . privateKey ;
5967 this . publicKey = keyPair . publicKey ;
68+ this . certificate = certificateFromPrivateKey ( keyPair . privateKey ) ;
6069
6170 return ;
6271 }
6372
6473 // new key from pem string
6574 if ( pem ) {
66- const { key, isPublic } = keyFromPem ( pem ) ;
67-
68- this . keyIsPublic = isPublic ;
69- this . privateKey = isPublic ? null : key ;
70- this . publicKey = isPublic ? key : null ;
71-
75+ this . readFromPem ( pem ) ;
7276 return ;
7377 }
7478
7579 // new key from mod and exp
7680 if ( mod && exp ) {
77- const { key, isPublic } = keyFromModAndExp ( mod , exp ) ;
78-
79- this . keyIsPublic = isPublic ;
80- this . privateKey = isPublic ? null : key ;
81- this . publicKey = isPublic ? key : null ;
82-
81+ this . readFromModAndExp ( mod , exp ) ; // only used for H004
8382 return ;
8483 }
8584
8685 // not good
8786 throw new Error ( `Can not create key without ${ ! mod ? 'modulus' : 'exponent' } .` ) ;
8887 }
8988
89+ readFromPem ( pem ) {
90+ this . type = getKeyType ( pem ) ;
91+ switch ( this . type ) {
92+ case 'public' :
93+ this . publicKey = publicKeyFromPem ( pem ) ;
94+ this . privateKey = null ;
95+ this . certificate = null ;
96+ break ;
97+ case 'private' :
98+ this . privateKey = privateKeyFromPem ( pem ) ;
99+ this . publicKey = setRsaPublicKey ( this . privateKey . n , this . privateKey . e ) ;
100+ this . certificate = certificateFromPrivateKey ( this . privateKey ) ;
101+ break ;
102+ case 'certificate' :
103+ this . privateKey = null ;
104+ this . certificate = certificateFromPem ( pem ) ;
105+ this . publicKey = this . certificate . publicKey ;
106+ break ;
107+ default :
108+ throw new Error ( `Unknown key type: ${ this . type } ` ) ;
109+ }
110+ }
111+
112+ /**
113+ * Creates a public key from modulus and exponent
114+ * @param {Buffer } mod - the modulus
115+ * @param {Buffer } exp - the exponent
116+ */
117+ readFromModAndExp ( mod , exp ) {
118+ const bnMod = new BigInteger ( mod . toString ( 'hex' ) , 16 ) ;
119+ const bnExp = new BigInteger ( exp . toString ( 'hex' ) , 16 ) ;
120+
121+ this . type = 'public' ;
122+ this . publicKey = rsa . setPublicKey ( bnMod , bnExp ) ;
123+ this . privateKey = null ;
124+ this . certificate = null ;
125+ }
126+
90127 static generate ( size = 2048 ) {
91128 return new Key ( { size } ) ;
92129 }
@@ -96,32 +133,31 @@ module.exports = class Key {
96133 }
97134
98135 n ( to = 'buff' ) {
99- const key = this . keyIsPublic ? this . publicKey : this . privateKey ;
136+ const key = this . privateKey || this . publicKey ;
100137 const keyN = Buffer . from ( key . n . toByteArray ( ) ) ;
101138
102139 return to === 'hex' ? keyN . toString ( 'hex' , 1 ) : keyN ;
103140 }
104141
105142 e ( to = 'buff' ) {
106- const key = this . keyIsPublic ? this . publicKey : this . privateKey ;
143+ const key = this . privateKey || this . publicKey ;
107144 const eKey = Buffer . from ( key . e . toByteArray ( ) ) ;
108145
109146 return to === 'hex' ? eKey . toString ( 'hex' ) : eKey ;
110147 }
111148
112149 d ( ) {
113- if ( this . keyIsPublic )
150+ if ( ! this . privateKey )
114151 throw new Error ( 'Can not get d component out of public key.' ) ;
115152
116153 return Buffer . from ( this . privateKey . d . toByteArray ( ) ) ;
117154 }
118155
119- isPrivate ( ) {
120- return ! this . keyIsPublic ;
121- }
156+ certificateBase64 ( ) {
157+ if ( ! this . certificate )
158+ throw new Error ( 'Certificate is not available.' ) ;
122159
123- isPublic ( ) {
124- return this . keyIsPublic ;
160+ return new X509Certificate ( certificateToPem ( this . certificate ) ) . raw . toString ( 'base64' ) ;
125161 }
126162
127163 // eslint-disable-next-line class-methods-use-this
@@ -133,6 +169,15 @@ module.exports = class Key {
133169 }
134170
135171 toPem ( ) {
136- return this . keyIsPublic ? publicKeyToPem ( this . publicKey ) : privateKeyToPem ( this . privateKey ) ;
172+ if ( this . privateKey )
173+ return privateKeyToPem ( this . privateKey ) ;
174+
175+ if ( this . certificate )
176+ return certificateToPem ( this . certificate ) ;
177+
178+ if ( this . publicKey )
179+ return publicKeyToPem ( this . publicKey ) ;
180+
181+ throw new Error ( 'No key found' ) ;
137182 }
138183} ;
0 commit comments