node-forge 0.7.5 → 0.8.2

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/x509.js CHANGED
@@ -251,8 +251,8 @@ var x509CertificateValidator = {
251
251
  constructed: true,
252
252
  captureAsn1: 'certSubject'
253
253
  },
254
- // SubjectPublicKeyInfo
255
- publicKeyValidator,
254
+ // SubjectPublicKeyInfo
255
+ publicKeyValidator,
256
256
  {
257
257
  // issuerUniqueID (optional)
258
258
  name: 'Certificate.TBSCertificate.issuerUniqueID',
@@ -464,32 +464,33 @@ var certificationRequestValidator = {
464
464
  captureAsn1: 'csr',
465
465
  value: [
466
466
  certificationRequestInfoValidator, {
467
- // AlgorithmIdentifier (signature algorithm)
468
- name: 'CertificationRequest.signatureAlgorithm',
469
- tagClass: asn1.Class.UNIVERSAL,
470
- type: asn1.Type.SEQUENCE,
471
- constructed: true,
472
- value: [{
473
- // algorithm
474
- name: 'CertificationRequest.signatureAlgorithm.algorithm',
467
+ // AlgorithmIdentifier (signature algorithm)
468
+ name: 'CertificationRequest.signatureAlgorithm',
475
469
  tagClass: asn1.Class.UNIVERSAL,
476
- type: asn1.Type.OID,
477
- constructed: false,
478
- capture: 'csrSignatureOid'
470
+ type: asn1.Type.SEQUENCE,
471
+ constructed: true,
472
+ value: [{
473
+ // algorithm
474
+ name: 'CertificationRequest.signatureAlgorithm.algorithm',
475
+ tagClass: asn1.Class.UNIVERSAL,
476
+ type: asn1.Type.OID,
477
+ constructed: false,
478
+ capture: 'csrSignatureOid'
479
+ }, {
480
+ name: 'CertificationRequest.signatureAlgorithm.parameters',
481
+ tagClass: asn1.Class.UNIVERSAL,
482
+ optional: true,
483
+ captureAsn1: 'csrSignatureParams'
484
+ }]
479
485
  }, {
480
- name: 'CertificationRequest.signatureAlgorithm.parameters',
486
+ // signature
487
+ name: 'CertificationRequest.signature',
481
488
  tagClass: asn1.Class.UNIVERSAL,
482
- optional: true,
483
- captureAsn1: 'csrSignatureParams'
484
- }]
485
- }, {
486
- // signature
487
- name: 'CertificationRequest.signature',
488
- tagClass: asn1.Class.UNIVERSAL,
489
- type: asn1.Type.BITSTRING,
490
- constructed: false,
491
- captureBitStringValue: 'csrSignature'
492
- }]
489
+ type: asn1.Type.BITSTRING,
490
+ constructed: false,
491
+ captureBitStringValue: 'csrSignature'
492
+ }
493
+ ]
493
494
  };
494
495
 
495
496
  /**
@@ -709,13 +710,15 @@ pki.certificateFromPem = function(pem, computeHash, strict) {
709
710
  if(msg.type !== 'CERTIFICATE' &&
710
711
  msg.type !== 'X509 CERTIFICATE' &&
711
712
  msg.type !== 'TRUSTED CERTIFICATE') {
712
- var error = new Error('Could not convert certificate from PEM; PEM header type ' +
713
+ var error = new Error(
714
+ 'Could not convert certificate from PEM; PEM header type ' +
713
715
  'is not "CERTIFICATE", "X509 CERTIFICATE", or "TRUSTED CERTIFICATE".');
714
716
  error.headerType = msg.type;
715
717
  throw error;
716
718
  }
717
719
  if(msg.procType && msg.procType.type === 'ENCRYPTED') {
718
- throw new Error('Could not convert certificate from PEM; PEM is encrypted.');
720
+ throw new Error(
721
+ 'Could not convert certificate from PEM; PEM is encrypted.');
719
722
  }
720
723
 
721
724
  // convert DER to ASN.1 object
@@ -822,14 +825,14 @@ pki.getPublicKeyFingerprint = function(key, options) {
822
825
 
823
826
  var bytes;
824
827
  switch(type) {
825
- case 'RSAPublicKey':
826
- bytes = asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes();
827
- break;
828
- case 'SubjectPublicKeyInfo':
829
- bytes = asn1.toDer(pki.publicKeyToAsn1(key)).getBytes();
830
- break;
831
- default:
832
- throw new Error('Unknown fingerprint type "' + options.type + '".');
828
+ case 'RSAPublicKey':
829
+ bytes = asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes();
830
+ break;
831
+ case 'SubjectPublicKeyInfo':
832
+ bytes = asn1.toDer(pki.publicKeyToAsn1(key)).getBytes();
833
+ break;
834
+ default:
835
+ throw new Error('Unknown fingerprint type "' + options.type + '".');
833
836
  }
834
837
 
835
838
  // hash public key bytes
@@ -1062,7 +1065,8 @@ pki.createCertificate = function() {
1062
1065
  if(!cert.issued(child)) {
1063
1066
  var issuer = child.issuer;
1064
1067
  var subject = cert.subject;
1065
- var error = new Error('The parent certificate did not issue the given child ' +
1068
+ var error = new Error(
1069
+ 'The parent certificate did not issue the given child ' +
1066
1070
  'certificate; the child certificate\'s issuer does not match the ' +
1067
1071
  'parent\'s subject.');
1068
1072
  error.expectedIssuer = issuer.attributes;
@@ -1076,24 +1080,24 @@ pki.createCertificate = function() {
1076
1080
  if(child.signatureOid in oids) {
1077
1081
  var oid = oids[child.signatureOid];
1078
1082
  switch(oid) {
1079
- case 'sha1WithRSAEncryption':
1080
- md = forge.md.sha1.create();
1081
- break;
1082
- case 'md5WithRSAEncryption':
1083
- md = forge.md.md5.create();
1084
- break;
1085
- case 'sha256WithRSAEncryption':
1086
- md = forge.md.sha256.create();
1087
- break;
1088
- case 'sha384WithRSAEncryption':
1089
- md = forge.md.sha384.create();
1090
- break;
1091
- case 'sha512WithRSAEncryption':
1092
- md = forge.md.sha512.create();
1093
- break;
1094
- case 'RSASSA-PSS':
1095
- md = forge.md.sha256.create();
1096
- break;
1083
+ case 'sha1WithRSAEncryption':
1084
+ md = forge.md.sha1.create();
1085
+ break;
1086
+ case 'md5WithRSAEncryption':
1087
+ md = forge.md.md5.create();
1088
+ break;
1089
+ case 'sha256WithRSAEncryption':
1090
+ md = forge.md.sha256.create();
1091
+ break;
1092
+ case 'sha384WithRSAEncryption':
1093
+ md = forge.md.sha384.create();
1094
+ break;
1095
+ case 'sha512WithRSAEncryption':
1096
+ md = forge.md.sha512.create();
1097
+ break;
1098
+ case 'RSASSA-PSS':
1099
+ md = forge.md.sha256.create();
1100
+ break;
1097
1101
  }
1098
1102
  }
1099
1103
  if(md === null) {
@@ -1113,44 +1117,44 @@ pki.createCertificate = function() {
1113
1117
  var scheme;
1114
1118
 
1115
1119
  switch(child.signatureOid) {
1116
- case oids.sha1WithRSAEncryption:
1117
- scheme = undefined; /* use PKCS#1 v1.5 padding scheme */
1118
- break;
1119
- case oids['RSASSA-PSS']:
1120
- var hash, mgf;
1121
-
1122
- /* initialize mgf */
1123
- hash = oids[child.signatureParameters.mgf.hash.algorithmOid];
1124
- if(hash === undefined || forge.md[hash] === undefined) {
1125
- var error = new Error('Unsupported MGF hash function.');
1126
- error.oid = child.signatureParameters.mgf.hash.algorithmOid;
1127
- error.name = hash;
1128
- throw error;
1129
- }
1120
+ case oids.sha1WithRSAEncryption:
1121
+ scheme = undefined; /* use PKCS#1 v1.5 padding scheme */
1122
+ break;
1123
+ case oids['RSASSA-PSS']:
1124
+ var hash, mgf;
1125
+
1126
+ /* initialize mgf */
1127
+ hash = oids[child.signatureParameters.mgf.hash.algorithmOid];
1128
+ if(hash === undefined || forge.md[hash] === undefined) {
1129
+ var error = new Error('Unsupported MGF hash function.');
1130
+ error.oid = child.signatureParameters.mgf.hash.algorithmOid;
1131
+ error.name = hash;
1132
+ throw error;
1133
+ }
1130
1134
 
1131
- mgf = oids[child.signatureParameters.mgf.algorithmOid];
1132
- if(mgf === undefined || forge.mgf[mgf] === undefined) {
1133
- var error = new Error('Unsupported MGF function.');
1134
- error.oid = child.signatureParameters.mgf.algorithmOid;
1135
- error.name = mgf;
1136
- throw error;
1137
- }
1135
+ mgf = oids[child.signatureParameters.mgf.algorithmOid];
1136
+ if(mgf === undefined || forge.mgf[mgf] === undefined) {
1137
+ var error = new Error('Unsupported MGF function.');
1138
+ error.oid = child.signatureParameters.mgf.algorithmOid;
1139
+ error.name = mgf;
1140
+ throw error;
1141
+ }
1138
1142
 
1139
- mgf = forge.mgf[mgf].create(forge.md[hash].create());
1143
+ mgf = forge.mgf[mgf].create(forge.md[hash].create());
1140
1144
 
1141
- /* initialize hash function */
1142
- hash = oids[child.signatureParameters.hash.algorithmOid];
1143
- if(hash === undefined || forge.md[hash] === undefined) {
1144
- throw {
1145
- message: 'Unsupported RSASSA-PSS hash function.',
1146
- oid: child.signatureParameters.hash.algorithmOid,
1147
- name: hash
1148
- };
1149
- }
1145
+ /* initialize hash function */
1146
+ hash = oids[child.signatureParameters.hash.algorithmOid];
1147
+ if(hash === undefined || forge.md[hash] === undefined) {
1148
+ throw {
1149
+ message: 'Unsupported RSASSA-PSS hash function.',
1150
+ oid: child.signatureParameters.hash.algorithmOid,
1151
+ name: hash
1152
+ };
1153
+ }
1150
1154
 
1151
- scheme = forge.pss.create(forge.md[hash].create(), mgf,
1152
- child.signatureParameters.saltLength);
1153
- break;
1155
+ scheme = forge.pss.create(forge.md[hash].create(), mgf,
1156
+ child.signatureParameters.saltLength);
1157
+ break;
1154
1158
  }
1155
1159
 
1156
1160
  // verify signature on cert using public key
@@ -1334,24 +1338,24 @@ pki.certificateFromAsn1 = function(obj, computeHash) {
1334
1338
  if(cert.signatureOid in oids) {
1335
1339
  var oid = oids[cert.signatureOid];
1336
1340
  switch(oid) {
1337
- case 'sha1WithRSAEncryption':
1338
- cert.md = forge.md.sha1.create();
1339
- break;
1340
- case 'md5WithRSAEncryption':
1341
- cert.md = forge.md.md5.create();
1342
- break;
1343
- case 'sha256WithRSAEncryption':
1344
- cert.md = forge.md.sha256.create();
1345
- break;
1346
- case 'sha384WithRSAEncryption':
1347
- cert.md = forge.md.sha384.create();
1348
- break;
1349
- case 'sha512WithRSAEncryption':
1350
- cert.md = forge.md.sha512.create();
1351
- break;
1352
- case 'RSASSA-PSS':
1353
- cert.md = forge.md.sha256.create();
1354
- break;
1341
+ case 'sha1WithRSAEncryption':
1342
+ cert.md = forge.md.sha1.create();
1343
+ break;
1344
+ case 'md5WithRSAEncryption':
1345
+ cert.md = forge.md.md5.create();
1346
+ break;
1347
+ case 'sha256WithRSAEncryption':
1348
+ cert.md = forge.md.sha256.create();
1349
+ break;
1350
+ case 'sha384WithRSAEncryption':
1351
+ cert.md = forge.md.sha384.create();
1352
+ break;
1353
+ case 'sha512WithRSAEncryption':
1354
+ cert.md = forge.md.sha512.create();
1355
+ break;
1356
+ case 'RSASSA-PSS':
1357
+ cert.md = forge.md.sha256.create();
1358
+ break;
1355
1359
  }
1356
1360
  }
1357
1361
  if(cert.md === null) {
@@ -1598,24 +1602,24 @@ pki.certificateExtensionFromAsn1 = function(ext) {
1598
1602
 
1599
1603
  // Note: Support for types 1,2,6,7,8
1600
1604
  switch(gn.type) {
1601
- // rfc822Name
1602
- case 1:
1603
- // dNSName
1604
- case 2:
1605
- // uniformResourceIdentifier (URI)
1606
- case 6:
1607
- break;
1608
- // IPAddress
1609
- case 7:
1610
- // convert to IPv4/IPv6 string representation
1611
- altName.ip = forge.util.bytesToIP(gn.value);
1612
- break;
1613
- // registeredID
1614
- case 8:
1615
- altName.oid = asn1.derToOid(gn.value);
1616
- break;
1617
- default:
1618
- // unsupported
1605
+ // rfc822Name
1606
+ case 1:
1607
+ // dNSName
1608
+ case 2:
1609
+ // uniformResourceIdentifier (URI)
1610
+ case 6:
1611
+ break;
1612
+ // IPAddress
1613
+ case 7:
1614
+ // convert to IPv4/IPv6 string representation
1615
+ altName.ip = forge.util.bytesToIP(gn.value);
1616
+ break;
1617
+ // registeredID
1618
+ case 8:
1619
+ altName.oid = asn1.derToOid(gn.value);
1620
+ break;
1621
+ default:
1622
+ // unsupported
1619
1623
  }
1620
1624
  }
1621
1625
  } else if(e.name === 'subjectKeyIdentifier') {
@@ -1678,24 +1682,24 @@ pki.certificationRequestFromAsn1 = function(obj, computeHash) {
1678
1682
  if(csr.signatureOid in oids) {
1679
1683
  var oid = oids[csr.signatureOid];
1680
1684
  switch(oid) {
1681
- case 'sha1WithRSAEncryption':
1682
- csr.md = forge.md.sha1.create();
1683
- break;
1684
- case 'md5WithRSAEncryption':
1685
- csr.md = forge.md.md5.create();
1686
- break;
1687
- case 'sha256WithRSAEncryption':
1688
- csr.md = forge.md.sha256.create();
1689
- break;
1690
- case 'sha384WithRSAEncryption':
1691
- csr.md = forge.md.sha384.create();
1692
- break;
1693
- case 'sha512WithRSAEncryption':
1694
- csr.md = forge.md.sha512.create();
1695
- break;
1696
- case 'RSASSA-PSS':
1697
- csr.md = forge.md.sha256.create();
1698
- break;
1685
+ case 'sha1WithRSAEncryption':
1686
+ csr.md = forge.md.sha1.create();
1687
+ break;
1688
+ case 'md5WithRSAEncryption':
1689
+ csr.md = forge.md.md5.create();
1690
+ break;
1691
+ case 'sha256WithRSAEncryption':
1692
+ csr.md = forge.md.sha256.create();
1693
+ break;
1694
+ case 'sha384WithRSAEncryption':
1695
+ csr.md = forge.md.sha384.create();
1696
+ break;
1697
+ case 'sha512WithRSAEncryption':
1698
+ csr.md = forge.md.sha512.create();
1699
+ break;
1700
+ case 'RSASSA-PSS':
1701
+ csr.md = forge.md.sha256.create();
1702
+ break;
1699
1703
  }
1700
1704
  }
1701
1705
  if(csr.md === null) {
@@ -1848,28 +1852,29 @@ pki.createCertificationRequest = function() {
1848
1852
  // TODO: create DRY `OID to md` function
1849
1853
  var oid = oids[csr.signatureOid];
1850
1854
  switch(oid) {
1851
- case 'sha1WithRSAEncryption':
1852
- md = forge.md.sha1.create();
1853
- break;
1854
- case 'md5WithRSAEncryption':
1855
- md = forge.md.md5.create();
1856
- break;
1857
- case 'sha256WithRSAEncryption':
1858
- md = forge.md.sha256.create();
1859
- break;
1860
- case 'sha384WithRSAEncryption':
1861
- md = forge.md.sha384.create();
1862
- break;
1863
- case 'sha512WithRSAEncryption':
1864
- md = forge.md.sha512.create();
1865
- break;
1866
- case 'RSASSA-PSS':
1867
- md = forge.md.sha256.create();
1868
- break;
1855
+ case 'sha1WithRSAEncryption':
1856
+ md = forge.md.sha1.create();
1857
+ break;
1858
+ case 'md5WithRSAEncryption':
1859
+ md = forge.md.md5.create();
1860
+ break;
1861
+ case 'sha256WithRSAEncryption':
1862
+ md = forge.md.sha256.create();
1863
+ break;
1864
+ case 'sha384WithRSAEncryption':
1865
+ md = forge.md.sha384.create();
1866
+ break;
1867
+ case 'sha512WithRSAEncryption':
1868
+ md = forge.md.sha512.create();
1869
+ break;
1870
+ case 'RSASSA-PSS':
1871
+ md = forge.md.sha256.create();
1872
+ break;
1869
1873
  }
1870
1874
  }
1871
1875
  if(md === null) {
1872
- var error = new Error('Could not compute certification request digest. ' +
1876
+ var error = new Error(
1877
+ 'Could not compute certification request digest. ' +
1873
1878
  'Unknown signature OID.');
1874
1879
  error.signatureOid = csr.signatureOid;
1875
1880
  throw error;
@@ -1886,43 +1891,43 @@ pki.createCertificationRequest = function() {
1886
1891
  var scheme;
1887
1892
 
1888
1893
  switch(csr.signatureOid) {
1889
- case oids.sha1WithRSAEncryption:
1890
- /* use PKCS#1 v1.5 padding scheme */
1891
- break;
1892
- case oids['RSASSA-PSS']:
1893
- var hash, mgf;
1894
-
1895
- /* initialize mgf */
1896
- hash = oids[csr.signatureParameters.mgf.hash.algorithmOid];
1897
- if(hash === undefined || forge.md[hash] === undefined) {
1898
- var error = new Error('Unsupported MGF hash function.');
1899
- error.oid = csr.signatureParameters.mgf.hash.algorithmOid;
1900
- error.name = hash;
1901
- throw error;
1902
- }
1894
+ case oids.sha1WithRSAEncryption:
1895
+ /* use PKCS#1 v1.5 padding scheme */
1896
+ break;
1897
+ case oids['RSASSA-PSS']:
1898
+ var hash, mgf;
1899
+
1900
+ /* initialize mgf */
1901
+ hash = oids[csr.signatureParameters.mgf.hash.algorithmOid];
1902
+ if(hash === undefined || forge.md[hash] === undefined) {
1903
+ var error = new Error('Unsupported MGF hash function.');
1904
+ error.oid = csr.signatureParameters.mgf.hash.algorithmOid;
1905
+ error.name = hash;
1906
+ throw error;
1907
+ }
1903
1908
 
1904
- mgf = oids[csr.signatureParameters.mgf.algorithmOid];
1905
- if(mgf === undefined || forge.mgf[mgf] === undefined) {
1906
- var error = new Error('Unsupported MGF function.');
1907
- error.oid = csr.signatureParameters.mgf.algorithmOid;
1908
- error.name = mgf;
1909
- throw error;
1910
- }
1909
+ mgf = oids[csr.signatureParameters.mgf.algorithmOid];
1910
+ if(mgf === undefined || forge.mgf[mgf] === undefined) {
1911
+ var error = new Error('Unsupported MGF function.');
1912
+ error.oid = csr.signatureParameters.mgf.algorithmOid;
1913
+ error.name = mgf;
1914
+ throw error;
1915
+ }
1911
1916
 
1912
- mgf = forge.mgf[mgf].create(forge.md[hash].create());
1917
+ mgf = forge.mgf[mgf].create(forge.md[hash].create());
1913
1918
 
1914
- /* initialize hash function */
1915
- hash = oids[csr.signatureParameters.hash.algorithmOid];
1916
- if(hash === undefined || forge.md[hash] === undefined) {
1917
- var error = new Error('Unsupported RSASSA-PSS hash function.');
1918
- error.oid = csr.signatureParameters.hash.algorithmOid;
1919
- error.name = hash;
1920
- throw error;
1921
- }
1919
+ /* initialize hash function */
1920
+ hash = oids[csr.signatureParameters.hash.algorithmOid];
1921
+ if(hash === undefined || forge.md[hash] === undefined) {
1922
+ var error = new Error('Unsupported RSASSA-PSS hash function.');
1923
+ error.oid = csr.signatureParameters.hash.algorithmOid;
1924
+ error.name = hash;
1925
+ throw error;
1926
+ }
1922
1927
 
1923
- scheme = forge.pss.create(forge.md[hash].create(), mgf,
1924
- csr.signatureParameters.saltLength);
1925
- break;
1928
+ scheme = forge.pss.create(forge.md[hash].create(), mgf,
1929
+ csr.signatureParameters.saltLength);
1930
+ break;
1926
1931
  }
1927
1932
 
1928
1933
  // verify signature on csr using its public key
@@ -2272,6 +2277,15 @@ function _fillMissingExtensionFields(e, options) {
2272
2277
  asn1.Class.CONTEXT_SPECIFIC, altName.type, false,
2273
2278
  value));
2274
2279
  }
2280
+ } else if(e.name === 'nsComment' && options.cert) {
2281
+ // sanity check value is ASCII (req'd) and not too big
2282
+ if(!(/^[\x00-\x7F]*$/.test(e.comment)) ||
2283
+ (e.comment.length < 1) || (e.comment.length > 128)) {
2284
+ throw new Error('Invalid "nsComment" content.');
2285
+ }
2286
+ // IA5STRING opaque comment
2287
+ e.value = asn1.create(
2288
+ asn1.Class.UNIVERSAL, asn1.Type.IA5STRING, false, e.comment);
2275
2289
  } else if(e.name === 'subjectKeyIdentifier' && options.cert) {
2276
2290
  var ski = options.cert.generateSubjectKeyIdentifier();
2277
2291
  e.subjectKeyIdentifier = ski.toHex();
@@ -2308,15 +2322,17 @@ function _fillMissingExtensionFields(e, options) {
2308
2322
  seq.push(
2309
2323
  asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, false, serialNumber));
2310
2324
  }
2311
- } else if (e.name === 'cRLDistributionPoints') {
2325
+ } else if(e.name === 'cRLDistributionPoints') {
2312
2326
  e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2313
2327
  var seq = e.value.value;
2314
2328
 
2315
2329
  // Create sub SEQUENCE of DistributionPointName
2316
- var subSeq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2330
+ var subSeq = asn1.create(
2331
+ asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
2317
2332
 
2318
2333
  // Create fullName CHOICE
2319
- var fullNameGeneralNames = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, []);
2334
+ var fullNameGeneralNames = asn1.create(
2335
+ asn1.Class.CONTEXT_SPECIFIC, 0, true, []);
2320
2336
  var altName;
2321
2337
  for(var n = 0; n < e.altNames.length; ++n) {
2322
2338
  altName = e.altNames[n];
@@ -2345,7 +2361,8 @@ function _fillMissingExtensionFields(e, options) {
2345
2361
  }
2346
2362
 
2347
2363
  // Add to the parent SEQUENCE
2348
- subSeq.value.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [fullNameGeneralNames]));
2364
+ subSeq.value.push(asn1.create(
2365
+ asn1.Class.CONTEXT_SPECIFIC, 0, true, [fullNameGeneralNames]));
2349
2366
  seq.push(subSeq);
2350
2367
  }
2351
2368
 
@@ -2368,44 +2385,44 @@ function _fillMissingExtensionFields(e, options) {
2368
2385
  */
2369
2386
  function _signatureParametersToAsn1(oid, params) {
2370
2387
  switch(oid) {
2371
- case oids['RSASSA-PSS']:
2372
- var parts = [];
2373
-
2374
- if(params.hash.algorithmOid !== undefined) {
2375
- parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
2376
- asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2377
- asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2378
- asn1.oidToDer(params.hash.algorithmOid).getBytes()),
2379
- asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
2380
- ])
2381
- ]));
2382
- }
2388
+ case oids['RSASSA-PSS']:
2389
+ var parts = [];
2383
2390
 
2384
- if(params.mgf.algorithmOid !== undefined) {
2385
- parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
2386
- asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2387
- asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2388
- asn1.oidToDer(params.mgf.algorithmOid).getBytes()),
2391
+ if(params.hash.algorithmOid !== undefined) {
2392
+ parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
2389
2393
  asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2390
2394
  asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2391
- asn1.oidToDer(params.mgf.hash.algorithmOid).getBytes()),
2395
+ asn1.oidToDer(params.hash.algorithmOid).getBytes()),
2392
2396
  asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
2393
2397
  ])
2394
- ])
2395
- ]));
2396
- }
2398
+ ]));
2399
+ }
2397
2400
 
2398
- if(params.saltLength !== undefined) {
2399
- parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [
2400
- asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
2401
- asn1.integerToDer(params.saltLength).getBytes())
2402
- ]));
2403
- }
2401
+ if(params.mgf.algorithmOid !== undefined) {
2402
+ parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
2403
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2404
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2405
+ asn1.oidToDer(params.mgf.algorithmOid).getBytes()),
2406
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2407
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
2408
+ asn1.oidToDer(params.mgf.hash.algorithmOid).getBytes()),
2409
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
2410
+ ])
2411
+ ])
2412
+ ]));
2413
+ }
2404
2414
 
2405
- return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, parts);
2415
+ if(params.saltLength !== undefined) {
2416
+ parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [
2417
+ asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
2418
+ asn1.integerToDer(params.saltLength).getBytes())
2419
+ ]));
2420
+ }
2421
+
2422
+ return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, parts);
2406
2423
 
2407
- default:
2408
- return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '');
2424
+ default:
2425
+ return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '');
2409
2426
  }
2410
2427
  }
2411
2428
 
@@ -2465,6 +2482,29 @@ function _CRIAttributesToAsn1(csr) {
2465
2482
  return rval;
2466
2483
  }
2467
2484
 
2485
+ const jan_1_1950 = new Date('1950-01-01T00:00:00Z');
2486
+ const jan_1_2050 = new Date('2050-01-01T00:00:00Z');
2487
+
2488
+ /**
2489
+ * Converts a Date object to ASN.1
2490
+ * Handles the different format before and after 1st January 2050
2491
+ *
2492
+ * @param date date object.
2493
+ *
2494
+ * @return the ASN.1 object representing the date.
2495
+ */
2496
+ function _dateToAsn1(date) {
2497
+ if(date >= jan_1_1950 && date < jan_1_2050) {
2498
+ return asn1.create(
2499
+ asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false,
2500
+ asn1.dateToUtcTime(date));
2501
+ } else {
2502
+ return asn1.create(
2503
+ asn1.Class.UNIVERSAL, asn1.Type.GENERALIZEDTIME, false,
2504
+ asn1.dateToGeneralizedTime(date));
2505
+ }
2506
+ }
2507
+
2468
2508
  /**
2469
2509
  * Gets the ASN.1 TBSCertificate part of an X.509v3 certificate.
2470
2510
  *
@@ -2474,6 +2514,8 @@ function _CRIAttributesToAsn1(csr) {
2474
2514
  */
2475
2515
  pki.getTBSCertificate = function(cert) {
2476
2516
  // TBSCertificate
2517
+ var notBefore = _dateToAsn1(cert.validity.notBefore);
2518
+ var notAfter = _dateToAsn1(cert.validity.notAfter);
2477
2519
  var tbs = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2478
2520
  // version
2479
2521
  asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
@@ -2497,12 +2539,8 @@ pki.getTBSCertificate = function(cert) {
2497
2539
  _dnToAsn1(cert.issuer),
2498
2540
  // validity
2499
2541
  asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
2500
- // notBefore
2501
- asn1.create(asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false,
2502
- asn1.dateToUtcTime(cert.validity.notBefore)),
2503
- // notAfter
2504
- asn1.create(asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false,
2505
- asn1.dateToUtcTime(cert.validity.notAfter))
2542
+ notBefore,
2543
+ notAfter
2506
2544
  ]),
2507
2545
  // subject
2508
2546
  _dnToAsn1(cert.subject),
@@ -2749,7 +2787,7 @@ pki.createCaStore = function(certs) {
2749
2787
 
2750
2788
  ensureSubjectHasHash(cert.subject);
2751
2789
 
2752
- if(!caStore.hasCertificate(cert)) { // avoid duplicate certificates in store
2790
+ if(!caStore.hasCertificate(cert)) { // avoid duplicate certificates in store
2753
2791
  if(cert.subject.hash in caStore.certs) {
2754
2792
  // subject hash already exists, append to array
2755
2793
  var tmp = caStore.certs[cert.subject.hash];
@@ -2874,7 +2912,7 @@ pki.createCaStore = function(certs) {
2874
2912
  // produce subject hash if it doesn't exist
2875
2913
  if(!subject.hash) {
2876
2914
  var md = forge.md.sha1.create();
2877
- subject.attributes = pki.RDNAttributesAsArray(_dnToAsn1(subject), md);
2915
+ subject.attributes = pki.RDNAttributesAsArray(_dnToAsn1(subject), md);
2878
2916
  subject.hash = md.digest().toHex();
2879
2917
  }
2880
2918
  }
@@ -2910,7 +2948,13 @@ pki.certificateError = {
2910
2948
  * @param caStore a certificate store to verify against.
2911
2949
  * @param chain the certificate chain to verify, with the root or highest
2912
2950
  * authority at the end (an array of certificates).
2913
- * @param verify called for every certificate in the chain.
2951
+ * @param options a callback to be called for every certificate in the chain or
2952
+ * an object with:
2953
+ * verify a callback to be called for every certificate in the
2954
+ * chain
2955
+ * validityCheckDate the date against which the certificate
2956
+ * validity period should be checked. Pass null to not check
2957
+ * the validity period. By default, the current date is used.
2914
2958
  *
2915
2959
  * The verify callback has the following signature:
2916
2960
  *
@@ -2926,7 +2970,7 @@ pki.certificateError = {
2926
2970
  *
2927
2971
  * @return true if successful, error thrown if not.
2928
2972
  */
2929
- pki.verifyCertificateChain = function(caStore, chain, verify) {
2973
+ pki.verifyCertificateChain = function(caStore, chain, options) {
2930
2974
  /* From: RFC3280 - Internet X.509 Public Key Infrastructure Certificate
2931
2975
  Section 6: Certification Path Validation
2932
2976
  See inline parentheticals related to this particular implementation.
@@ -3056,13 +3100,26 @@ pki.verifyCertificateChain = function(caStore, chain, verify) {
3056
3100
  CAs that may appear below a CA before only end-entity certificates
3057
3101
  may be issued. */
3058
3102
 
3103
+ // if a verify callback is passed as the third parameter, package it within
3104
+ // the options object. This is to support a legacy function signature that
3105
+ // expected the verify callback as the third parameter.
3106
+ if(typeof options === 'function') {
3107
+ options = {verify: options};
3108
+ }
3109
+ options = options || {};
3110
+
3059
3111
  // copy cert chain references to another array to protect against changes
3060
3112
  // in verify callback
3061
3113
  chain = chain.slice(0);
3062
3114
  var certs = chain.slice(0);
3063
3115
 
3064
- // get current date
3065
- var now = new Date();
3116
+ var validityCheckDate = options.validityCheckDate;
3117
+ // if no validityCheckDate is specified, default to the current date. Make
3118
+ // sure to maintain the value null because it indicates that the validity
3119
+ // period should not be checked.
3120
+ if(typeof validityCheckDate === 'undefined') {
3121
+ validityCheckDate = new Date();
3122
+ }
3066
3123
 
3067
3124
  // verify each cert in the chain using its parent, where the parent
3068
3125
  // is either the next in the chain or from the CA store
@@ -3074,15 +3131,20 @@ pki.verifyCertificateChain = function(caStore, chain, verify) {
3074
3131
  var parent = null;
3075
3132
  var selfSigned = false;
3076
3133
 
3077
- // 1. check valid time
3078
- if(now < cert.validity.notBefore || now > cert.validity.notAfter) {
3079
- error = {
3080
- message: 'Certificate is not valid yet or has expired.',
3081
- error: pki.certificateError.certificate_expired,
3082
- notBefore: cert.validity.notBefore,
3083
- notAfter: cert.validity.notAfter,
3084
- now: now
3085
- };
3134
+ if(validityCheckDate) {
3135
+ // 1. check valid time
3136
+ if(validityCheckDate < cert.validity.notBefore ||
3137
+ validityCheckDate > cert.validity.notAfter) {
3138
+ error = {
3139
+ message: 'Certificate is not valid yet or has expired.',
3140
+ error: pki.certificateError.certificate_expired,
3141
+ notBefore: cert.validity.notBefore,
3142
+ notAfter: cert.validity.notAfter,
3143
+ // TODO: we might want to reconsider renaming 'now' to
3144
+ // 'validityCheckDate' should this API be changed in the future.
3145
+ now: validityCheckDate
3146
+ };
3147
+ }
3086
3148
  }
3087
3149
 
3088
3150
  // 2. verify with parent from chain or CA store
@@ -3229,7 +3291,7 @@ pki.verifyCertificateChain = function(caStore, chain, verify) {
3229
3291
 
3230
3292
  // call application callback
3231
3293
  var vfd = (error === null) ? true : error.error;
3232
- var ret = verify ? verify(vfd, depth, certs) : vfd;
3294
+ var ret = options.verify ? options.verify(vfd, depth, certs) : vfd;
3233
3295
  if(ret === true) {
3234
3296
  // clear any set error
3235
3297
  error = null;
@@ -3247,7 +3309,7 @@ pki.verifyCertificateChain = function(caStore, chain, verify) {
3247
3309
  // set custom message and error
3248
3310
  if(typeof ret === 'object' && !forge.util.isArray(ret)) {
3249
3311
  if(ret.message) {
3250
- error.message = ret.message;
3312
+ error.message = ret.message;
3251
3313
  }
3252
3314
  if(ret.error) {
3253
3315
  error.error = ret.error;