forked from stateofca/opencred
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x509 Verification after VC verification.
- Loading branch information
1 parent
6027363
commit 3ca6853
Showing
13 changed files
with
718 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
import * as x509 from '@peculiar/x509'; | ||
import {Certificate, CertificateRevocationList} from 'pkijs'; | ||
import {createPublicKey, X509Certificate} from 'node:crypto'; | ||
import {config} from '../config/config.js'; | ||
import ocsp from 'ocsp'; | ||
|
||
const checkDates = cert => { | ||
const now = new Date(); | ||
const validFrom = new Date(cert.validFrom); | ||
const validTo = new Date(cert.validTo); | ||
if(now < validFrom || now > validTo) { | ||
return {verified: false, errors: [ | ||
'Certificate is not valid at the current time' | ||
]}; | ||
} | ||
return {verified: true, errors: []}; | ||
}; | ||
|
||
const checkKeyUsage = cert => { | ||
const pec = new x509.X509Certificate(cert.toString()); | ||
const keyUsages = pec.getExtension('2.5.29.15'); // key usage extension | ||
const digitalSignatureBit = 0; | ||
|
||
// Check to make sure key usage includes digital signatures | ||
if((keyUsages.usages & (1 << digitalSignatureBit)) === 0) { | ||
return {verified: false, errors: [ | ||
`Certificate doesn't have digital signature key usage` | ||
]}; | ||
} | ||
return {verified: true, errors: []}; | ||
}; | ||
|
||
const checkRevocation = async (cert, issuer) => { | ||
const errors = []; | ||
if(typeof cert.infoAccess !== 'undefined') { | ||
await new Promise(resolve => { | ||
ocsp.check({ | ||
cert: cert.raw, | ||
issuer: issuer.raw | ||
}, function(err, res) { | ||
if(err !== null || res.type !== 'good') { | ||
errors.push('x509 certificate has been revoked (OCSP)'); | ||
} | ||
resolve(); | ||
}); | ||
}); | ||
} | ||
|
||
/* | ||
* TEMPORARILY DISABLED | ||
const certificate = Certificate.fromBER(cert.raw); | ||
const ext = certificate.extensions.find(ext => ext.extnID === '2.5.29.31'); | ||
if(ext) { | ||
const crlURIs = new Set([]); | ||
for(const points of ext.parsedValue.distributionPoints) { | ||
for(const point of points.distributionPoint) { | ||
crlURIs.add(point.value); | ||
} | ||
} | ||
for(const uri of crlURIs) { | ||
const resp = await fetch(uri); | ||
if(resp.status === 200) { | ||
const crlBER = await resp.arrayBuffer(); | ||
const crl = CertificateRevocationList.fromBER(crlBER); | ||
const revoked = crl.isCertificateRevoked(Certificate.fromBER(cert.raw)); | ||
if(revoked) { | ||
errors.push(`x509 certificate has been revoked (CRL)`); | ||
} | ||
} else { | ||
errors.push(`Failed to query CRL at ${uri} - Received ${resp.status}`); | ||
} | ||
} | ||
} | ||
*/ | ||
return {verified: errors.length === 0, errors}; | ||
}; | ||
|
||
const checkSignature = async (cert, parentCert) => { | ||
const errors = []; | ||
|
||
// verify signature | ||
const verified = cert.verify(parentCert.publicKey); | ||
if(!verified) { | ||
errors.push(`X509 certificate invalid`); | ||
} | ||
|
||
return {verified: errors.length === 0, errors}; | ||
}; | ||
|
||
const checkTrust = async certs => { | ||
let errors = []; | ||
let i = 0; | ||
for(const cert of certs) { | ||
if(i < certs.length - 1) { | ||
const issued = cert.checkIssued(certs[i + 1]); | ||
if(!issued) { | ||
errors.push(`X509 certificate at index ${i} not issued by parent.`); | ||
} else { | ||
const verified = await checkSignature(cert, certs[i + 1]); | ||
if(!verified.verified) { | ||
errors = errors.concat(verified.errors); | ||
} | ||
const revocation = await checkRevocation(cert, certs[i + 1]); | ||
if(!revocation.verified) { | ||
errors = errors.concat(revocation.errors); | ||
} | ||
} | ||
} else { | ||
// Issuer in CA Store | ||
let found = false; | ||
for(const caCertRaw of config.caStore) { | ||
const caCert = new X509Certificate(caCertRaw); | ||
if(certs[i].checkIssued(caCert)) { | ||
found = true; | ||
const verified = await checkSignature(certs[i], caCert); | ||
if(!verified.verified) { | ||
errors = errors.concat(verified.errors); | ||
} | ||
const revocation = await checkRevocation(certs[i], caCert); | ||
if(!revocation.verified) { | ||
errors = errors.concat(revocation.errors); | ||
} | ||
break; | ||
} | ||
} | ||
if(!found) { | ||
errors.push( | ||
`Issuer of X509 certificate at index ${i} not found in CA store`); | ||
} | ||
} | ||
i++; | ||
} | ||
return {verified: errors.length === 0, errors}; | ||
}; | ||
|
||
export const verifyX509 = async certs => { | ||
try { | ||
let errors = []; | ||
for(const cert of certs) { | ||
// Verify Expiration Date | ||
const datesVerify = checkDates(cert); | ||
if(!datesVerify.verified) { | ||
errors = errors.concat(datesVerify.errors); | ||
} | ||
|
||
// Check Key Usage | ||
const keyUsageVerify = checkKeyUsage(cert); | ||
if(!keyUsageVerify.verified) { | ||
errors = errors.concat(keyUsageVerify.errors); | ||
} | ||
} | ||
|
||
// Check Trust | ||
const trustVerify = await checkTrust(certs); | ||
if(!trustVerify.verified) { | ||
errors = errors.concat(trustVerify.errors); | ||
} | ||
return {verified: errors.length === 0, errors}; | ||
} catch(e) { | ||
console.error(e); | ||
return {verified: false, errors: [e.message]}; | ||
} | ||
}; | ||
|
||
export const verifyJWKx509 = async jwk => { | ||
try { | ||
const certs = jwk.x5c.map(x5c => | ||
new X509Certificate(Buffer.from(x5c, 'base64'))); | ||
|
||
// Verify public key matches certificate | ||
const key = createPublicKey({key: jwk, format: 'jwk'}); | ||
if(!certs[0].publicKey.equals(key)) { | ||
return { | ||
verified: false, | ||
errors: ['Public key is not found in leaf certificate'] | ||
}; | ||
} | ||
return await verifyX509(certs); | ||
} catch(e) { | ||
console.error(e); | ||
return {verified: false, errors: [e.message]}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIFSzCCBDOgAwIBAgIQSueVSfqavj8QDxekeOFpCTANBgkqhkiG9w0BAQsFADCB | ||
kDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G | ||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNjA0BgNV | ||
BAMTLUNPTU9ETyBSU0EgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBD | ||
QTAeFw0xNTA0MDkwMDAwMDBaFw0xNTA0MTIyMzU5NTlaMFkxITAfBgNVBAsTGERv | ||
bWFpbiBDb250cm9sIFZhbGlkYXRlZDEdMBsGA1UECxMUUG9zaXRpdmVTU0wgV2ls | ||
ZGNhcmQxFTATBgNVBAMUDCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD | ||
ggEPADCCAQoCggEBAMIE7PiM7gTCs9hQ1XBYzJMY61yoaEmwIrX5lZ6xKyx2PmzA | ||
S2BMTOqytMAPgLaw+XLJhgL5XEFdEyt/ccRLvOmULlA3pmccYYz2QULFRtMWhyef | ||
dOsKnRFSJiFzbIRMeVXk0WvoBj1IFVKtsyjbqv9u/2CVSndrOfEk0TG23U3AxPxT | ||
uW1CrbV8/q71FdIzSOciccfCFHpsKOo3St/qbLVytH5aohbcabFXRNsKEqveww9H | ||
dFxBIuGa+RuT5q0iBikusbpJHAwnnqP7i/dAcgCskgjZjFeEU4EFy+b+a1SYQCeF | ||
xxC7c3DvaRhBB0VVfPlkPz0sw6l865MaTIbRyoUCAwEAAaOCAdUwggHRMB8GA1Ud | ||
IwQYMBaAFJCvajqUWgvYkOoSVnPfQ7Q6KNrnMB0GA1UdDgQWBBSd7sF7gQs6R2lx | ||
GH0RN5O8pRs/+zAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUE | ||
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQIC | ||
BzArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAI | ||
BgZngQwBAgEwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5jb21vZG9jYS5j | ||
b20vQ09NT0RPUlNBRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCB | ||
hQYIKwYBBQUHAQEEeTB3ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LmNvbW9kb2Nh | ||
LmNvbS9DT01PRE9SU0FEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0 | ||
MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wIwYDVR0RBBww | ||
GoIMKi5iYWRzc2wuY29tggpiYWRzc2wuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBq | ||
evHa/wMHcnjFZqFPRkMOXxQhjHUa6zbgH6QQFezaMyV8O7UKxwE4PSf9WNnM6i1p | ||
OXy+l+8L1gtY54x/v7NMHfO3kICmNnwUW+wHLQI+G1tjWxWrAPofOxkt3+IjEBEH | ||
fnJ/4r+3ABuYLyw/zoWaJ4wQIghBK4o+gk783SHGVnRwpDTysUCeK1iiWQ8dSO/r | ||
ET7BSp68ZVVtxqPv1dSWzfGuJ/ekVxQ8lEEFeouhN0fX9X3c+s5vMaKwjOrMEpsi | ||
8TRwz311SotoKQwe6Zaoz7ASH1wq7mcvf71z81oBIgxw+s1F73hczg36TuHvzmWf | ||
RwxPuzZEaFZcVlmtqoq8 | ||
-----END CERTIFICATE----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIFUTCCBDmgAwIBAgIQB5g2A63jmQghnKAMJ7yKbDANBgkqhkiG9w0BAQsFADBh | ||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 | ||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD | ||
QTAeFw0yMDA3MTYxMjI1MjdaFw0yMzA1MzEyMzU5NTlaMFkxCzAJBgNVBAYTAlVT | ||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKlJhcGlkU1NMIFRMUyBE | ||
ViBSU0EgTWl4ZWQgU0hBMjU2IDIwMjAgQ0EtMTCCASIwDQYJKoZIhvcNAQEBBQAD | ||
ggEPADCCAQoCggEBANpuQ1VVmXvZlaJmxGVYotAMFzoApohbJAeNpzN+49LbgkrM | ||
Lv2tblII8H43vN7UFumxV7lJdPwLP22qa0sV9cwCr6QZoGEobda+4pufG0aSfHQC | ||
QhulaqKpPcYYOPjTwgqJA84AFYj8l/IeQ8n01VyCurMIHA478ts2G6GGtEx0ucnE | ||
fV2QHUL64EC2yh7ybboo5v8nFWV4lx/xcfxoxkFTVnAIRgHrH2vUdOiV9slOix3z | ||
5KPs2rK2bbach8Sh5GSkgp2HRoS/my0tCq1vjyLJeP0aNwPd3rk5O8LiffLev9j+ | ||
UKZo0tt0VvTLkdGmSN4h1mVY6DnGfOwp1C5SK0MCAwEAAaOCAgswggIHMB0GA1Ud | ||
DgQWBBSkjeW+fHnkcCNtLik0rSNY3PUxfzAfBgNVHSMEGDAWgBQD3lA1VtFMu2bw | ||
o+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEG | ||
CCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAmMCQG | ||
CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wewYDVR0fBHQwcjA3 | ||
oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9v | ||
dENBLmNybDA3oDWgM4YxaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 | ||
R2xvYmFsUm9vdENBLmNybDCBzgYDVR0gBIHGMIHDMIHABgRVHSAAMIG3MCgGCCsG | ||
AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGKBggrBgEFBQcC | ||
AjB+DHxBbnkgdXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0ZXMgYWNj | ||
ZXB0YW5jZSBvZiB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1lbnQgbG9jYXRlZCBh | ||
dCBodHRwczovL3d3dy5kaWdpY2VydC5jb20vcnBhLXVhMA0GCSqGSIb3DQEBCwUA | ||
A4IBAQAi49xtSOuOygBycy50quCThG45xIdUAsQCaXFVRa9asPaB/jLINXJL3qV9 | ||
J0Gh2bZM0k4yOMeAMZ57smP6JkcJihhOFlfQa18aljd+xNc6b+GX6oFcCHGr+gsE | ||
yPM8qvlKGxc5T5eHVzV6jpjpyzl6VEKpaxH6gdGVpQVgjkOR9yY9XAUlFnzlOCpq | ||
sm7r2ZUKpDfrhUnVzX2nSM15XSj48rVBBAnGJWkLPijlACd3sWFMVUiKRz1C5PZy | ||
el2l7J/W4d99KFLSYgoy5GDmARpwLc//fXfkr40nMY8ibCmxCsjXQTe0fJbtrrLL | ||
yWQlk9VDV296EI/kQOJNLVEkJ54P | ||
-----END CERTIFICATE----- |
Oops, something went wrong.