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/CHANGELOG.md +58 -0
- package/README.md +41 -39
- package/dist/forge.all.min.js +1 -1
- package/dist/forge.min.js +1 -1
- package/flash/package.json +28 -0
- package/lib/aesCipherSuites.js +2 -4
- package/lib/cipherModes.js +1 -1
- package/lib/des.js +2 -1
- package/lib/kem.js +2 -2
- package/lib/oids.js +2 -0
- package/lib/pkcs1.js +1 -1
- package/lib/pkcs7.js +30 -16
- package/lib/prng.js +6 -7
- package/lib/random.js +7 -7
- package/lib/rsa.js +162 -100
- package/lib/sha1.js +6 -6
- package/lib/sha512.js +1 -1
- package/lib/tls.js +43 -30
- package/lib/util.js +17 -2
- package/lib/x509.js +313 -251
- package/package.json +10 -13
package/lib/x509.js
CHANGED
|
@@ -251,8 +251,8 @@ var x509CertificateValidator = {
|
|
|
251
251
|
constructed: true,
|
|
252
252
|
captureAsn1: 'certSubject'
|
|
253
253
|
},
|
|
254
|
-
|
|
255
|
-
|
|
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
|
-
|
|
468
|
-
|
|
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.
|
|
477
|
-
constructed:
|
|
478
|
-
|
|
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
|
-
|
|
486
|
+
// signature
|
|
487
|
+
name: 'CertificationRequest.signature',
|
|
481
488
|
tagClass: asn1.Class.UNIVERSAL,
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
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(
|
|
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
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
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
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
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
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
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
|
-
|
|
1143
|
+
mgf = forge.mgf[mgf].create(forge.md[hash].create());
|
|
1140
1144
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
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
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
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
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
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
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
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
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
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
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
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(
|
|
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
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
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
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
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
|
-
|
|
1917
|
+
mgf = forge.mgf[mgf].create(forge.md[hash].create());
|
|
1913
1918
|
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
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
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
2372
|
-
|
|
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
|
-
|
|
2385
|
-
|
|
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.
|
|
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
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2408
|
-
|
|
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
|
-
|
|
2501
|
-
|
|
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)) {
|
|
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 =
|
|
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
|
|
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,
|
|
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
|
-
|
|
3065
|
-
|
|
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
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
error
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
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
|
-
|
|
3312
|
+
error.message = ret.message;
|
|
3251
3313
|
}
|
|
3252
3314
|
if(ret.error) {
|
|
3253
3315
|
error.error = ret.error;
|