node-forge 1.2.1 → 1.3.0

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/lib/asn1.js CHANGED
@@ -411,6 +411,8 @@ var _getValueLength = function(bytes, remaining) {
411
411
  * @param [options] object with options or boolean strict flag
412
412
  * [strict] true to be strict when checking value lengths, false to
413
413
  * allow truncated values (default: true).
414
+ * [parseAllBytes] true to ensure all bytes are parsed
415
+ * (default: true)
414
416
  * [decodeBitStrings] true to attempt to decode the content of
415
417
  * BIT STRINGs (not OCTET STRINGs) using strict mode. Note that
416
418
  * without schema support to understand the data context this can
@@ -418,24 +420,31 @@ var _getValueLength = function(bytes, remaining) {
418
420
  * flag will be deprecated or removed as soon as schema support is
419
421
  * available. (default: true)
420
422
  *
423
+ * @throws Will throw an error for various malformed input conditions.
424
+ *
421
425
  * @return the parsed asn1 object.
422
426
  */
423
427
  asn1.fromDer = function(bytes, options) {
424
428
  if(options === undefined) {
425
429
  options = {
426
430
  strict: true,
431
+ parseAllBytes: true,
427
432
  decodeBitStrings: true
428
433
  };
429
434
  }
430
435
  if(typeof options === 'boolean') {
431
436
  options = {
432
437
  strict: options,
438
+ parseAllBytes: true,
433
439
  decodeBitStrings: true
434
440
  };
435
441
  }
436
442
  if(!('strict' in options)) {
437
443
  options.strict = true;
438
444
  }
445
+ if(!('parseAllBytes' in options)) {
446
+ options.parseAllBytes = true;
447
+ }
439
448
  if(!('decodeBitStrings' in options)) {
440
449
  options.decodeBitStrings = true;
441
450
  }
@@ -445,7 +454,15 @@ asn1.fromDer = function(bytes, options) {
445
454
  bytes = forge.util.createBuffer(bytes);
446
455
  }
447
456
 
448
- return _fromDer(bytes, bytes.length(), 0, options);
457
+ var byteCount = bytes.length();
458
+ var value = _fromDer(bytes, bytes.length(), 0, options);
459
+ if(options.parseAllBytes && bytes.length() !== 0) {
460
+ var error = new Error('Unparsed DER bytes remain after ASN.1 parsing.');
461
+ error.byteCount = byteCount;
462
+ error.remaining = bytes.length();
463
+ throw error;
464
+ }
465
+ return value;
449
466
  };
450
467
 
451
468
  /**
@@ -566,7 +583,6 @@ function _fromDer(bytes, remaining, depth, options) {
566
583
  start = bytes.length();
567
584
  var subOptions = {
568
585
  // enforce strict mode to avoid parsing ASN.1 from plain data
569
- verbose: options.verbose,
570
586
  strict: true,
571
587
  decodeBitStrings: true
572
588
  };
@@ -615,6 +631,7 @@ function _fromDer(bytes, remaining, depth, options) {
615
631
  }
616
632
  } else {
617
633
  value = bytes.getBytes(length);
634
+ remaining -= length;
618
635
  }
619
636
  }
620
637
 
@@ -1391,7 +1408,16 @@ asn1.prettyPrint = function(obj, level, indentation) {
1391
1408
  }
1392
1409
  rval += '0x' + forge.util.bytesToHex(obj.value);
1393
1410
  } else if(obj.type === asn1.Type.UTF8) {
1394
- rval += forge.util.decodeUtf8(obj.value);
1411
+ try {
1412
+ rval += forge.util.decodeUtf8(obj.value);
1413
+ } catch(e) {
1414
+ if(e.message === 'URI malformed') {
1415
+ rval +=
1416
+ '0x' + forge.util.bytesToHex(obj.value) + ' (malformed UTF8)';
1417
+ } else {
1418
+ throw e;
1419
+ }
1420
+ }
1395
1421
  } else if(obj.type === asn1.Type.PRINTABLESTRING ||
1396
1422
  obj.type === asn1.Type.IA5String) {
1397
1423
  rval += obj.value;
package/lib/oids.js CHANGED
@@ -47,6 +47,10 @@ _IN('1.3.14.3.2.29', 'sha1WithRSASignature');
47
47
  _IN('2.16.840.1.101.3.4.2.1', 'sha256');
48
48
  _IN('2.16.840.1.101.3.4.2.2', 'sha384');
49
49
  _IN('2.16.840.1.101.3.4.2.3', 'sha512');
50
+ _IN('2.16.840.1.101.3.4.2.4', 'sha224');
51
+ _IN('2.16.840.1.101.3.4.2.5', 'sha512-224');
52
+ _IN('2.16.840.1.101.3.4.2.6', 'sha512-256');
53
+ _IN('1.2.840.113549.2.2', 'md2');
50
54
  _IN('1.2.840.113549.2.5', 'md5');
51
55
 
52
56
  // pkcs#7 content types
package/lib/rsa.js CHANGED
@@ -264,6 +264,40 @@ var publicKeyValidator = forge.pki.rsa.publicKeyValidator = {
264
264
  }]
265
265
  };
266
266
 
267
+ // validator for a DigestInfo structure
268
+ var digestInfoValidator = {
269
+ name: 'DigestInfo',
270
+ tagClass: asn1.Class.UNIVERSAL,
271
+ type: asn1.Type.SEQUENCE,
272
+ constructed: true,
273
+ value: [{
274
+ name: 'DigestInfo.DigestAlgorithm',
275
+ tagClass: asn1.Class.UNIVERSAL,
276
+ type: asn1.Type.SEQUENCE,
277
+ constructed: true,
278
+ value: [{
279
+ name: 'DigestInfo.DigestAlgorithm.algorithmIdentifier',
280
+ tagClass: asn1.Class.UNIVERSAL,
281
+ type: asn1.Type.OID,
282
+ constructed: false,
283
+ capture: 'algorithmIdentifier'
284
+ }, {
285
+ // NULL paramters
286
+ name: 'DigestInfo.DigestAlgorithm.parameters',
287
+ tagClass: asn1.Class.UNIVERSAL,
288
+ type: asn1.Type.NULL,
289
+ constructed: false
290
+ }]
291
+ }, {
292
+ // digest
293
+ name: 'DigestInfo.digest',
294
+ tagClass: asn1.Class.UNIVERSAL,
295
+ type: asn1.Type.OCTETSTRING,
296
+ constructed: false,
297
+ capture: 'digest'
298
+ }]
299
+ };
300
+
267
301
  /**
268
302
  * Wrap digest in DigestInfo object.
269
303
  *
@@ -1092,15 +1126,27 @@ pki.setRsaPublicKey = pki.rsa.setPublicKey = function(n, e) {
1092
1126
  * a Forge PSS object for RSASSA-PSS,
1093
1127
  * 'NONE' or null for none, DigestInfo will not be expected, but
1094
1128
  * PKCS#1 v1.5 padding will still be used.
1129
+ * @param options optional verify options
1130
+ * _parseAllDigestBytes testing flag to control parsing of all
1131
+ * digest bytes. Unsupported and not for general usage.
1132
+ * (default: true)
1095
1133
  *
1096
1134
  * @return true if the signature was verified, false if not.
1097
1135
  */
1098
- key.verify = function(digest, signature, scheme) {
1136
+ key.verify = function(digest, signature, scheme, options) {
1099
1137
  if(typeof scheme === 'string') {
1100
1138
  scheme = scheme.toUpperCase();
1101
1139
  } else if(scheme === undefined) {
1102
1140
  scheme = 'RSASSA-PKCS1-V1_5';
1103
1141
  }
1142
+ if(options === undefined) {
1143
+ options = {
1144
+ _parseAllDigestBytes: true
1145
+ };
1146
+ }
1147
+ if(!('_parseAllDigestBytes' in options)) {
1148
+ options._parseAllDigestBytes = true;
1149
+ }
1104
1150
 
1105
1151
  if(scheme === 'RSASSA-PKCS1-V1_5') {
1106
1152
  scheme = {
@@ -1108,9 +1154,41 @@ pki.setRsaPublicKey = pki.rsa.setPublicKey = function(n, e) {
1108
1154
  // remove padding
1109
1155
  d = _decodePkcs1_v1_5(d, key, true);
1110
1156
  // d is ASN.1 BER-encoded DigestInfo
1111
- var obj = asn1.fromDer(d);
1157
+ var obj = asn1.fromDer(d, {
1158
+ parseAllBytes: options._parseAllDigestBytes
1159
+ });
1160
+
1161
+ // validate DigestInfo
1162
+ var capture = {};
1163
+ var errors = [];
1164
+ if(!asn1.validate(obj, digestInfoValidator, capture, errors)) {
1165
+ var error = new Error(
1166
+ 'ASN.1 object does not contain a valid RSASSA-PKCS1-v1_5 ' +
1167
+ 'DigestInfo value.');
1168
+ error.errors = errors;
1169
+ throw error;
1170
+ }
1171
+ // check hash algorithm identifier
1172
+ // see PKCS1-v1-5DigestAlgorithms in RFC 8017
1173
+ // FIXME: add support to vaidator for strict value choices
1174
+ var oid = asn1.derToOid(capture.algorithmIdentifier);
1175
+ if(!(oid === forge.oids.md2 ||
1176
+ oid === forge.oids.md5 ||
1177
+ oid === forge.oids.sha1 ||
1178
+ oid === forge.oids.sha224 ||
1179
+ oid === forge.oids.sha256 ||
1180
+ oid === forge.oids.sha384 ||
1181
+ oid === forge.oids.sha512 ||
1182
+ oid === forge.oids['sha512-224'] ||
1183
+ oid === forge.oids['sha512-256'])) {
1184
+ var error = new Error(
1185
+ 'Unknown RSASSA-PKCS1-v1_5 DigestAlgorithm identifier.');
1186
+ error.oid = oid;
1187
+ throw error;
1188
+ }
1189
+
1112
1190
  // compare the given digest to the decrypted one
1113
- return digest === obj.value[1].value;
1191
+ return digest === capture.digest;
1114
1192
  }
1115
1193
  };
1116
1194
  } else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-forge",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "JavaScript implementations of network transports, cryptography, ciphers, PKI, message digests, and various utilities.",
5
5
  "homepage": "https://github.com/digitalbazaar/forge",
6
6
  "author": {