2
2
3
3
const ObjectId = require ( 'mongodb' ) . ObjectId ;
4
4
const fingerprint = require ( 'key-fingerprint' ) . fingerprint ;
5
- const forge = require ( 'node-forge' ) ;
6
5
const crypto = require ( 'crypto' ) ;
7
6
const tools = require ( './tools' ) ;
8
7
const { publish, DKIM_CREATED , DKIM_UPDATED , DKIM_DELETED } = require ( './events' ) ;
@@ -11,6 +10,8 @@ const { encrypt, decrypt } = require('./encrypt');
11
10
const { promisify } = require ( 'util' ) ;
12
11
const generateKeyPair = promisify ( crypto . generateKeyPair ) ;
13
12
13
+ const ASN1_PADDING = 'MC4CAQAwBQYDK2VwBCIEIA==' ;
14
+
14
15
class DkimHandler {
15
16
constructor ( options ) {
16
17
options = options || { } ;
@@ -47,6 +48,7 @@ class DkimHandler {
47
48
48
49
let privateKeyPem = options . privateKey ;
49
50
let publicKeyPem ;
51
+ let publicKeyDer ;
50
52
51
53
if ( ! privateKeyPem ) {
52
54
let keyPair = await this . generateKey ( ) ;
@@ -61,12 +63,28 @@ class DkimHandler {
61
63
}
62
64
63
65
if ( ! publicKeyPem ) {
64
- // extract public key from private key using Forge
65
- let privateKey = forge . pki . privateKeyFromPem ( privateKeyPem ) ;
66
- let publicKey = forge . pki . setRsaPublicKey ( privateKey . n , privateKey . e ) ;
67
- publicKeyPem = forge . pki . publicKeyToPem ( publicKey ) ;
66
+ // extract public key from private key
67
+
68
+ // 1) check that privateKeyPem is ED25519 raw key, which length is 44
69
+ if ( privateKeyPem . length === 44 ) {
70
+ // privateKeyPem is actually a raw ED25519 base64 string with length of 44
71
+ // convert raw ED25519 key to PEM formatted private key
72
+ privateKeyPem = `-----BEGIN PRIVATE KEY-----
73
+ ${ Buffer . concat ( [ Buffer . from ( ASN1_PADDING , 'base64' ) , Buffer . from ( privateKeyPem , 'base64' ) ] ) . toString ( 'base64' ) }
74
+ -----END PRIVATE KEY-----` ;
75
+ }
76
+
77
+ const publicKey = crypto . createPublicKey ( { key : privateKeyPem , format : 'pem' } ) ;
78
+
79
+ publicKeyPem = publicKey . export ( { type : 'spki' , format : 'pem' } ) ;
68
80
69
- if ( ! publicKeyPem ) {
81
+ if ( publicKey . asymmetricKeyType === 'ed25519' ) {
82
+ publicKeyDer = publicKey . export ( { format : 'der' , type : 'spki' } ) . subarray ( 12 ) . toString ( 'base64' ) ;
83
+ } else if ( publicKey . asymmetricKeyType === 'rsa' ) {
84
+ publicKeyDer = publicKey . export ( { format : 'der' , type : 'spki' } ) . toString ( 'base64' ) ;
85
+ }
86
+
87
+ if ( ! publicKeyPem && ! publicKeyDer ) {
70
88
let err = new Error ( 'Failed to generate public key' ) ;
71
89
err . responseCode = 500 ;
72
90
err . code = 'KeyGenereateError' ;
@@ -78,9 +96,11 @@ class DkimHandler {
78
96
try {
79
97
fp = fingerprint ( privateKeyPem , 'sha256' , true ) ;
80
98
81
- let ciphered = crypto . publicEncrypt ( publicKeyPem , Buffer . from ( 'secretvalue' ) ) ;
82
- let deciphered = crypto . privateDecrypt ( privateKeyPem , ciphered ) ;
83
- if ( deciphered . toString ( ) !== 'secretvalue' ) {
99
+ const testData = Buffer . from ( 'secretvalue' ) ;
100
+ const signature = crypto . sign ( null , testData , privateKeyPem ) ;
101
+ const verificationResult = crypto . verify ( null , testData , publicKeyPem , signature ) ;
102
+
103
+ if ( ! verificationResult ) {
84
104
throw new Error ( 'Was not able to use key for encryption' ) ;
85
105
}
86
106
} catch ( E ) {
@@ -98,6 +118,7 @@ class DkimHandler {
98
118
selector,
99
119
privateKey : privateKeyPem ,
100
120
publicKey : publicKeyPem ,
121
+ publicKeyDer,
101
122
fingerprint : fp ,
102
123
created : new Date ( ) ,
103
124
latest : true
@@ -170,7 +191,7 @@ class DkimHandler {
170
191
publicKey : dkimData . publicKey ,
171
192
dnsTxt : {
172
193
name : dkimData . selector + '._domainkey.' + dkimData . domain ,
173
- value : 'v=DKIM1;t=s;p=' + dkimData . publicKey . replace ( / ^ - . * - $ / gm , '' ) . replace ( / \s / g , '' )
194
+ value : 'v=DKIM1;t=s;p=' + dkimData . publicKeyDer
174
195
}
175
196
} ;
176
197
}
0 commit comments