node-forge 0.6.38 → 0.6.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +1 -0
- package/bower.json +1 -1
- package/js/oids.js +1 -0
- package/js/x509.js +30 -0
- package/nodejs/test/util.js +81 -4
- package/nodejs/test/x509.js +79 -1
- package/package.json +3 -3
package/.travis.yml
CHANGED
package/bower.json
CHANGED
package/js/oids.js
CHANGED
|
@@ -196,6 +196,7 @@ oids['2.5.29.32'] = 'certificatePolicies';
|
|
|
196
196
|
oids['2.5.29.33'] = 'policyMappings';
|
|
197
197
|
oids['2.5.29.34'] = 'policyConstraints'; // deprecated use .36
|
|
198
198
|
oids['2.5.29.35'] = 'authorityKeyIdentifier';
|
|
199
|
+
oids['authorityKeyIdentifier'] = '2.5.29.35';
|
|
199
200
|
oids['2.5.29.36'] = 'policyConstraints';
|
|
200
201
|
oids['2.5.29.37'] = 'extKeyUsage';
|
|
201
202
|
oids['extKeyUsage'] = '2.5.29.37';
|
package/js/x509.js
CHANGED
|
@@ -2278,6 +2278,36 @@ function _fillMissingExtensionFields(e, options) {
|
|
|
2278
2278
|
// OCTETSTRING w/digest
|
|
2279
2279
|
e.value = asn1.create(
|
|
2280
2280
|
asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, ski.getBytes());
|
|
2281
|
+
} else if(e.name === 'authorityKeyIdentifier' && options.cert) {
|
|
2282
|
+
// SYNTAX SEQUENCE
|
|
2283
|
+
e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
|
|
2284
|
+
var seq = e.value.value;
|
|
2285
|
+
|
|
2286
|
+
if(e.keyIdentifier) {
|
|
2287
|
+
var keyIdentifier = (e.keyIdentifier === true ?
|
|
2288
|
+
options.cert.generateSubjectKeyIdentifier().getBytes() :
|
|
2289
|
+
e.keyIdentifier);
|
|
2290
|
+
seq.push(
|
|
2291
|
+
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, false, keyIdentifier));
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
if(e.authorityCertIssuer) {
|
|
2295
|
+
var authorityCertIssuer = [
|
|
2296
|
+
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 4, true, [
|
|
2297
|
+
_dnToAsn1(e.authorityCertIssuer === true ?
|
|
2298
|
+
options.cert.issuer : e.authorityCertIssuer)
|
|
2299
|
+
])
|
|
2300
|
+
];
|
|
2301
|
+
seq.push(
|
|
2302
|
+
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, authorityCertIssuer));
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
if(e.serialNumber) {
|
|
2306
|
+
var serialNumber = forge.util.hexToBytes(e.serialNumber === true ?
|
|
2307
|
+
options.cert.serialNumber : e.serialNumber);
|
|
2308
|
+
seq.push(
|
|
2309
|
+
asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, false, serialNumber));
|
|
2310
|
+
}
|
|
2281
2311
|
}
|
|
2282
2312
|
|
|
2283
2313
|
// ensure value has been defined by now
|
package/nodejs/test/util.js
CHANGED
|
@@ -383,7 +383,63 @@ function Tests(ASSERT, UTIL) {
|
|
|
383
383
|
ASSERT.equal(addr, '2001:db8:0:1:1:1:1:1');
|
|
384
384
|
});
|
|
385
385
|
|
|
386
|
+
it('should convert "foo" to its UTF-8 representation', function() {
|
|
387
|
+
if(typeof Uint8Array === 'undefined') {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
var result = UTIL.text.utf8.encode('foo');
|
|
391
|
+
ASSERT.equal(result.byteLength, 3);
|
|
392
|
+
ASSERT.equal(result[0], 102);
|
|
393
|
+
ASSERT.equal(result[1], 111);
|
|
394
|
+
ASSERT.equal(result[2], 111);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('should convert "foo" from its UTF-8 representation', function() {
|
|
398
|
+
if(typeof Uint8Array === 'undefined') {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
var bytes = new Uint8Array([102, 111, 111]);
|
|
402
|
+
// FIXME: remove try/catch once phantomjs supports apply(TypedArray)
|
|
403
|
+
// or a fallback is implemented
|
|
404
|
+
try {
|
|
405
|
+
var result = UTIL.text.utf8.decode(bytes);
|
|
406
|
+
ASSERT.equal(result, 'foo');
|
|
407
|
+
} catch(e) {
|
|
408
|
+
ASSERT.isTrue(e instanceof TypeError);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
it('should convert "\ud83c\udc00" to its UTF-8 representation', function() {
|
|
413
|
+
if(typeof Uint8Array === 'undefined') {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
var result = UTIL.text.utf8.encode('\ud83c\udc00');
|
|
417
|
+
ASSERT.equal(result.byteLength, 4);
|
|
418
|
+
ASSERT.equal(result[0], 240);
|
|
419
|
+
ASSERT.equal(result[1], 159);
|
|
420
|
+
ASSERT.equal(result[2], 128);
|
|
421
|
+
ASSERT.equal(result[3], 128);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it('should convert "\ud83c\udc00" from its UTF-8 representation', function() {
|
|
425
|
+
if(typeof Uint8Array === 'undefined') {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
var bytes = new Uint8Array([240, 159, 128, 128]);
|
|
429
|
+
// FIXME: remove try/catch once phantomjs supports apply(TypedArray)
|
|
430
|
+
// or a fallback is implemented
|
|
431
|
+
try {
|
|
432
|
+
var result = UTIL.text.utf8.decode(bytes);
|
|
433
|
+
ASSERT.equal(result, '\ud83c\udc00');
|
|
434
|
+
} catch(e) {
|
|
435
|
+
ASSERT.isTrue(e instanceof TypeError);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
|
|
386
439
|
it('should convert "foo" to its UTF-16 representation', function() {
|
|
440
|
+
if(typeof Uint8Array === 'undefined') {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
387
443
|
var result = UTIL.text.utf16.encode('foo');
|
|
388
444
|
ASSERT.equal(result.byteLength, 6);
|
|
389
445
|
ASSERT.equal(result[0], 102);
|
|
@@ -395,12 +451,24 @@ function Tests(ASSERT, UTIL) {
|
|
|
395
451
|
});
|
|
396
452
|
|
|
397
453
|
it('should convert "foo" from its UTF-16 representation', function() {
|
|
454
|
+
if(typeof Uint8Array === 'undefined') {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
398
457
|
var bytes = new Uint8Array([102, 0, 111, 0, 111, 0]);
|
|
399
|
-
|
|
400
|
-
|
|
458
|
+
// FIXME: remove try/catch once phantomjs supports apply(TypedArray)
|
|
459
|
+
// or a fallback is implemented
|
|
460
|
+
try {
|
|
461
|
+
var result = UTIL.text.utf16.decode(bytes);
|
|
462
|
+
ASSERT.equal(result, 'foo');
|
|
463
|
+
} catch(e) {
|
|
464
|
+
ASSERT.isTrue(e instanceof TypeError);
|
|
465
|
+
}
|
|
401
466
|
});
|
|
402
467
|
|
|
403
468
|
it('should convert "\ud83c\udc00" to its UTF-16 representation', function() {
|
|
469
|
+
if(typeof Uint8Array === 'undefined') {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
404
472
|
var result = UTIL.text.utf16.encode('\ud83c\udc00');
|
|
405
473
|
ASSERT.equal(result.byteLength, 4);
|
|
406
474
|
ASSERT.equal(result[0], 60);
|
|
@@ -410,9 +478,18 @@ function Tests(ASSERT, UTIL) {
|
|
|
410
478
|
});
|
|
411
479
|
|
|
412
480
|
it('should convert "\ud83c\udc00" from its UTF-16 representation', function() {
|
|
481
|
+
if(typeof Uint8Array === 'undefined') {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
413
484
|
var bytes = new Uint8Array([60, 216, 0, 220]);
|
|
414
|
-
|
|
415
|
-
|
|
485
|
+
// FIXME: remove try/catch once phantomjs supports apply(TypedArray)
|
|
486
|
+
// or a fallback is implemented
|
|
487
|
+
try {
|
|
488
|
+
var result = UTIL.text.utf16.decode(bytes);
|
|
489
|
+
ASSERT.equal(result, '\ud83c\udc00');
|
|
490
|
+
} catch(e) {
|
|
491
|
+
ASSERT.isTrue(e instanceof TypeError);
|
|
492
|
+
}
|
|
416
493
|
});
|
|
417
494
|
});
|
|
418
495
|
}
|
package/nodejs/test/x509.js
CHANGED
|
@@ -202,6 +202,71 @@ function Tests(ASSERT, PKI, MD, UTIL) {
|
|
|
202
202
|
ASSERT.ok(certificate.verify(certificate));
|
|
203
203
|
});
|
|
204
204
|
|
|
205
|
+
it('should generate a certificate with authorityKeyIdentifier extension', function() {
|
|
206
|
+
var keys = {
|
|
207
|
+
privateKey: PKI.privateKeyFromPem(_pem.privateKey),
|
|
208
|
+
publicKey: PKI.publicKeyFromPem(_pem.publicKey)
|
|
209
|
+
};
|
|
210
|
+
var attrs = [{
|
|
211
|
+
name: 'commonName',
|
|
212
|
+
value: 'example.org'
|
|
213
|
+
}, {
|
|
214
|
+
name: 'countryName',
|
|
215
|
+
value: 'US'
|
|
216
|
+
}, {
|
|
217
|
+
shortName: 'ST',
|
|
218
|
+
value: 'Virginia'
|
|
219
|
+
}, {
|
|
220
|
+
name: 'localityName',
|
|
221
|
+
value: 'Blacksburg'
|
|
222
|
+
}, {
|
|
223
|
+
name: 'organizationName',
|
|
224
|
+
value: 'Test'
|
|
225
|
+
}, {
|
|
226
|
+
shortName: 'OU',
|
|
227
|
+
value: 'Test'
|
|
228
|
+
}];
|
|
229
|
+
var cert = createCertificate({
|
|
230
|
+
publicKey: keys.publicKey,
|
|
231
|
+
signingKey: keys.privateKey,
|
|
232
|
+
extensions: [{
|
|
233
|
+
name: 'authorityKeyIdentifier',
|
|
234
|
+
keyIdentifier: true,
|
|
235
|
+
authorityCertIssuer: true,
|
|
236
|
+
serialNumber: true
|
|
237
|
+
}],
|
|
238
|
+
serialNumber: '01',
|
|
239
|
+
subject: attrs,
|
|
240
|
+
issuer: attrs,
|
|
241
|
+
isCA: true
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// verify certificate encoding/parsing
|
|
245
|
+
var pem = PKI.certificateToPem(cert);
|
|
246
|
+
cert = PKI.certificateFromPem(pem);
|
|
247
|
+
|
|
248
|
+
// verify authorityKeyIdentifier extension
|
|
249
|
+
var index = findIndex(cert.extensions, {id: '2.5.29.35'});
|
|
250
|
+
ASSERT.ok(index !== -1);
|
|
251
|
+
var ext = cert.extensions[index];
|
|
252
|
+
ASSERT.equal(ext.name, 'authorityKeyIdentifier');
|
|
253
|
+
ASSERT.equal(ext.value, UTIL.hexToBytes(
|
|
254
|
+
'3081888014f57563e0c75d6e9b03fafdb2fd72349f23030300a16da46b30693114' +
|
|
255
|
+
'30120603550403130b6578616d706c652e6f7267310b3009060355040613025553' +
|
|
256
|
+
'3111300f0603550408130856697267696e6961311330110603550407130a426c61' +
|
|
257
|
+
'636b7362757267310d300b060355040a130454657374310d300b060355040b1304' +
|
|
258
|
+
'54657374820101'));
|
|
259
|
+
|
|
260
|
+
// verify certificate chain
|
|
261
|
+
var caStore = PKI.createCaStore();
|
|
262
|
+
caStore.addCertificate(cert);
|
|
263
|
+
PKI.verifyCertificateChain(caStore, [cert], function(vfd, depth, chain) {
|
|
264
|
+
ASSERT.equal(vfd, true);
|
|
265
|
+
ASSERT.ok(cert.verifySubjectKeyIdentifier());
|
|
266
|
+
return true;
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
205
270
|
it('should generate and verify a self-signed certificate', function() {
|
|
206
271
|
var keys = {
|
|
207
272
|
privateKey: PKI.privateKeyFromPem(_pem.privateKey),
|
|
@@ -791,6 +856,19 @@ function Tests(ASSERT, PKI, MD, UTIL) {
|
|
|
791
856
|
});
|
|
792
857
|
});
|
|
793
858
|
|
|
859
|
+
function findIndex(array, predicateObj) {
|
|
860
|
+
var result = -1;
|
|
861
|
+
array.forEach(function(el, index) {
|
|
862
|
+
var match = Object.keys(predicateObj).reduce(function(soFar, key) {
|
|
863
|
+
return soFar && el[key] === predicateObj[key];
|
|
864
|
+
}, true);
|
|
865
|
+
if(match) {
|
|
866
|
+
result = index;
|
|
867
|
+
}
|
|
868
|
+
});
|
|
869
|
+
return result;
|
|
870
|
+
}
|
|
871
|
+
|
|
794
872
|
function createCertificate(options) {
|
|
795
873
|
var publicKey = options.publicKey;
|
|
796
874
|
var signingKey = options.signingKey;
|
|
@@ -808,7 +886,7 @@ function Tests(ASSERT, PKI, MD, UTIL) {
|
|
|
808
886
|
cert.validity.notBefore.getFullYear() + 1);
|
|
809
887
|
cert.setSubject(subject);
|
|
810
888
|
cert.setIssuer(issuer);
|
|
811
|
-
var extensions = [];
|
|
889
|
+
var extensions = options.extensions || [];
|
|
812
890
|
if(isCA) {
|
|
813
891
|
extensions.push({
|
|
814
892
|
name: 'basicConstraints',
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-forge",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.39",
|
|
4
4
|
"description": "JavaScript implementations of network transports, cryptography, ciphers, PKI, message digests, and various utilities.",
|
|
5
|
-
"homepage": "
|
|
5
|
+
"homepage": "https://github.com/digitalbazaar/forge",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Digital Bazaar, Inc.",
|
|
8
8
|
"email": "support@digitalbazaar.com",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
32
|
-
"url": "
|
|
32
|
+
"url": "https://github.com/digitalbazaar/forge"
|
|
33
33
|
},
|
|
34
34
|
"bugs": {
|
|
35
35
|
"url": "https://github.com/digitalbazaar/forge/issues",
|