%PDF- <> %âãÏÓ endobj 2 0 obj <> endobj 3 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 28 0 R 29 0 R] /MediaBox[ 0 0 595.5 842.25] /Contents 4 0 R/Group<>/Tabs/S>> endobj ºaâÚÎΞ-ÌE1ÍØÄ÷{òò2ÿ ÛÖ^ÔÀá TÎ{¦?§®¥kuµùÕ5sLOšuY>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<> endobj 2 0 obj<>endobj 2 0 obj<>es 3 0 R>> endobj 2 0 obj<> ox[ 0.000000 0.000000 609.600000 935.600000]/Fi endobj 3 0 obj<> endobj 7 1 obj<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Subtype/Form>> stream
'use strict';
const asn1 = require('asn1.js');
const crypto = require('crypto');
const { writeFileSync } = require('fs');
const rfc5280 = require('asn1.js-rfc5280');
const BN = asn1.bignum;
const oid = {
commonName: [2, 5, 4, 3],
countryName: [2, 5, 4, 6],
localityName: [2, 5, 4, 7],
rsaEncryption: [1, 2, 840, 113549, 1, 1, 1],
sha256WithRSAEncryption: [1, 2, 840, 113549, 1, 1, 11],
xmppAddr: [1, 3, 6, 1, 5, 5, 7, 8, 5],
srvName: [1, 3, 6, 1, 5, 5, 7, 8, 7],
ocsp: [1, 3, 6, 1, 5, 5, 7, 48, 1],
caIssuers: [1, 3, 6, 1, 5, 5, 7, 48, 2],
privateUnrecognized: [1, 3, 9999, 12, 34]
};
const digest = 'SHA256';
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'pkcs1',
format: 'der'
}
});
writeFileSync('server-key.pem', privateKey.export({
type: 'pkcs8',
format: 'pem'
}));
const now = Date.now();
const days = 3650;
function utilType(name, fn) {
return asn1.define(name, function() {
this[fn]();
});
}
const Null_ = utilType('Null_', 'null_');
const null_ = Null_.encode('der');
const IA5String = utilType('IA5String', 'ia5str');
const PrintableString = utilType('PrintableString', 'printstr');
const UTF8String = utilType('UTF8String', 'utf8str');
const subjectCommonName = PrintableString.encode('evil.example.com', 'der');
const sans = [
{ type: 'dNSName', value: 'good.example.com, DNS:evil.example.com' },
{ type: 'uniformResourceIdentifier', value: 'http://example.com/' },
{ type: 'uniformResourceIdentifier', value: 'http://example.com/?a=b&c=d' },
{ type: 'uniformResourceIdentifier', value: 'http://example.com/a,b' },
{ type: 'uniformResourceIdentifier', value: 'http://example.com/a%2Cb' },
{
type: 'uniformResourceIdentifier',
value: 'http://example.com/a, DNS:good.example.com'
},
{ type: 'dNSName', value: Buffer.from('exämple.com', 'latin1') },
{ type: 'dNSName', value: '"evil.example.com"' },
{ type: 'iPAddress', value: Buffer.from('08080808', 'hex') },
{ type: 'iPAddress', value: Buffer.from('08080404', 'hex') },
{ type: 'iPAddress', value: Buffer.from('0008080404', 'hex') },
{ type: 'iPAddress', value: Buffer.from('000102030405', 'hex') },
{
type: 'iPAddress',
value: Buffer.from('0a0b0c0d0e0f0000000000007a7b7c7d', 'hex')
},
{ type: 'rfc822Name', value: 'foo@example.com' },
{ type: 'rfc822Name', value: 'foo@example.com, DNS:good.example.com' },
{
type: 'directoryName',
value: {
type: 'rdnSequence',
value: [
[
{
type: oid.countryName,
value: PrintableString.encode('DE', 'der')
}
],
[
{
type: oid.localityName,
value: UTF8String.encode('Hannover', 'der')
}
]
]
}
},
{
type: 'directoryName',
value: {
type: 'rdnSequence',
value: [
[
{
type: oid.countryName,
value: PrintableString.encode('DE', 'der')
}
],
[
{
type: oid.localityName,
value: UTF8String.encode('München', 'der')
}
]
]
}
},
{
type: 'directoryName',
value: {
type: 'rdnSequence',
value: [
[
{
type: oid.countryName,
value: PrintableString.encode('DE', 'der')
}
],
[
{
type: oid.localityName,
value: UTF8String.encode('Berlin, DNS:good.example.com', 'der')
}
]
]
}
},
{
type: 'directoryName',
value: {
type: 'rdnSequence',
value: [
[
{
type: oid.countryName,
value: PrintableString.encode('DE', 'der')
}
],
[
{
type: oid.localityName,
value: UTF8String.encode('Berlin, DNS:good.example.com\0evil.example.com', 'der')
}
]
]
}
},
{
type: 'directoryName',
value: {
type: 'rdnSequence',
value: [
[
{
type: oid.countryName,
value: PrintableString.encode('DE', 'der')
}
],
[
{
type: oid.localityName,
value: UTF8String.encode(
'Berlin, DNS:good.example.com\\\0evil.example.com', 'der')
}
]
]
}
},
{
type: 'directoryName',
value: {
type: 'rdnSequence',
value: [
[
{
type: oid.countryName,
value: PrintableString.encode('DE', 'der')
}
],
[
{
type: oid.localityName,
value: UTF8String.encode('Berlin\r\n', 'der')
}
]
]
}
},
{
type: 'directoryName',
value: {
type: 'rdnSequence',
value: [
[
{
type: oid.countryName,
value: PrintableString.encode('DE', 'der')
}
],
[
{
type: oid.localityName,
value: UTF8String.encode('Berlin/CN=good.example.com', 'der')
}
]
]
}
},
{
type: 'registeredID',
value: oid.sha256WithRSAEncryption
},
{
type: 'registeredID',
value: oid.privateUnrecognized
},
{
type: 'otherName',
value: {
'type-id': oid.xmppAddr,
value: UTF8String.encode('abc123', 'der')
}
},
{
type: 'otherName',
value: {
'type-id': oid.xmppAddr,
value: UTF8String.encode('abc123, DNS:good.example.com', 'der')
}
},
{
type: 'otherName',
value: {
'type-id': oid.xmppAddr,
value: UTF8String.encode('good.example.com\0abc123', 'der')
}
},
{
type: 'otherName',
value: {
'type-id': oid.privateUnrecognized,
value: UTF8String.encode('abc123', 'der')
}
},
{
type: 'otherName',
value: {
'type-id': oid.srvName,
value: IA5String.encode('abc123', 'der')
}
},
{
type: 'otherName',
value: {
'type-id': oid.srvName,
value: UTF8String.encode('abc123', 'der')
}
},
{
type: 'otherName',
value: {
'type-id': oid.srvName,
value: IA5String.encode('abc\0def', 'der')
}
}
];
for (let i = 0; i < sans.length; i++) {
const san = sans[i];
const tbs = {
version: 'v3',
serialNumber: new BN('01', 16),
signature: {
algorithm: oid.sha256WithRSAEncryption,
parameters: null_
},
issuer: {
type: 'rdnSequence',
value: [
[
{ type: oid.commonName, value: subjectCommonName }
]
]
},
validity: {
notBefore: { type: 'utcTime', value: now },
notAfter: { type: 'utcTime', value: now + days * 86400000 }
},
subject: {
type: 'rdnSequence',
value: [
[
{ type: oid.commonName, value: subjectCommonName }
]
]
},
subjectPublicKeyInfo: {
algorithm: {
algorithm: oid.rsaEncryption,
parameters: null_
},
subjectPublicKey: {
unused: 0,
data: publicKey
}
},
extensions: [
{
extnID: 'subjectAlternativeName',
critical: false,
extnValue: [san]
}
]
};
// Self-sign the certificate.
const tbsDer = rfc5280.TBSCertificate.encode(tbs, 'der');
const signature = crypto.createSign(digest).update(tbsDer).sign(privateKey);
// Construct the signed certificate.
const cert = {
tbsCertificate: tbs,
signatureAlgorithm: {
algorithm: oid.sha256WithRSAEncryption,
parameters: null_
},
signature: {
unused: 0,
data: signature
}
};
// Store the signed certificate.
const pem = rfc5280.Certificate.encode(cert, 'pem', {
label: 'CERTIFICATE'
});
writeFileSync(`./alt-${i}-cert.pem`, `${pem}\n`);
}
const infoAccessExtensions = [
[
{
accessMethod: oid.ocsp,
accessLocation: {
type: 'uniformResourceIdentifier',
value: 'http://good.example.com/\nOCSP - URI:http://evil.example.com/',
},
},
],
[
{
accessMethod: oid.caIssuers,
accessLocation: {
type: 'uniformResourceIdentifier',
value: 'http://ca.example.com/\nOCSP - URI:http://evil.example.com',
},
},
{
accessMethod: oid.ocsp,
accessLocation: {
type: 'dNSName',
value: 'good.example.com\nOCSP - URI:http://ca.nodejs.org/ca.cert',
},
},
],
[
{
accessMethod: oid.privateUnrecognized,
accessLocation: {
type: 'uniformResourceIdentifier',
value: 'http://ca.example.com/',
},
},
],
[
{
accessMethod: oid.ocsp,
accessLocation: {
type: 'otherName',
value: {
'type-id': oid.xmppAddr,
value: UTF8String.encode('good.example.com', 'der'),
},
},
},
{
accessMethod: oid.ocsp,
accessLocation: {
type: 'otherName',
value: {
'type-id': oid.privateUnrecognized,
value: UTF8String.encode('abc123', 'der')
},
},
},
{
accessMethod: oid.ocsp,
accessLocation: {
type: 'otherName',
value: {
'type-id': oid.srvName,
value: IA5String.encode('abc123', 'der')
}
}
},
],
[
{
accessMethod: oid.ocsp,
accessLocation: {
type: 'otherName',
value: {
'type-id': oid.xmppAddr,
value: UTF8String.encode('good.example.com\0abc123', 'der'),
},
},
},
],
];
for (let i = 0; i < infoAccessExtensions.length; i++) {
const infoAccess = infoAccessExtensions[i];
const tbs = {
version: 'v3',
serialNumber: new BN('01', 16),
signature: {
algorithm: oid.sha256WithRSAEncryption,
parameters: null_
},
issuer: {
type: 'rdnSequence',
value: [
[
{ type: oid.commonName, value: subjectCommonName }
]
]
},
validity: {
notBefore: { type: 'utcTime', value: now },
notAfter: { type: 'utcTime', value: now + days * 86400000 }
},
subject: {
type: 'rdnSequence',
value: [
[
{ type: oid.commonName, value: subjectCommonName }
]
]
},
subjectPublicKeyInfo: {
algorithm: {
algorithm: oid.rsaEncryption,
parameters: null_
},
subjectPublicKey: {
unused: 0,
data: publicKey
}
},
extensions: [
{
extnID: 'authorityInformationAccess',
critical: false,
extnValue: infoAccess
}
]
};
// Self-sign the certificate.
const tbsDer = rfc5280.TBSCertificate.encode(tbs, 'der');
const signature = crypto.createSign(digest).update(tbsDer).sign(privateKey);
// Construct the signed certificate.
const cert = {
tbsCertificate: tbs,
signatureAlgorithm: {
algorithm: oid.sha256WithRSAEncryption,
parameters: null_
},
signature: {
unused: 0,
data: signature
}
};
// Store the signed certificate.
const pem = rfc5280.Certificate.encode(cert, 'pem', {
label: 'CERTIFICATE'
});
writeFileSync(`./info-${i}-cert.pem`, `${pem}\n`);
}
const subjects = [
[
[
{ type: oid.localityName, value: UTF8String.encode('Somewhere') }
],
[
{ type: oid.commonName, value: UTF8String.encode('evil.example.com') }
]
],
[
[
{
type: oid.localityName,
value: UTF8String.encode('Somewhere\0evil.example.com'),
}
]
],
[
[
{
type: oid.localityName,
value: UTF8String.encode('Somewhere\nCN=evil.example.com')
}
]
],
[
[
{
type: oid.localityName,
value: UTF8String.encode('Somewhere, CN = evil.example.com')
}
]
],
[
[
{
type: oid.localityName,
value: UTF8String.encode('Somewhere/CN=evil.example.com')
}
]
],
[
[
{
type: oid.localityName,
value: UTF8String.encode('M\u00fcnchen\\\nCN=evil.example.com')
}
]
],
[
[
{ type: oid.localityName, value: UTF8String.encode('Somewhere') },
{ type: oid.commonName, value: UTF8String.encode('evil.example.com') },
]
],
[
[
{
type: oid.localityName,
value: UTF8String.encode('Somewhere + CN=evil.example.com'),
}
]
],
[
[
{ type: oid.localityName, value: UTF8String.encode('L1') },
{ type: oid.localityName, value: UTF8String.encode('L2') },
],
[
{ type: oid.localityName, value: UTF8String.encode('L3') },
]
],
[
[
{ type: oid.localityName, value: UTF8String.encode('L1') },
],
[
{ type: oid.localityName, value: UTF8String.encode('L2') },
],
[
{ type: oid.localityName, value: UTF8String.encode('L3') },
],
],
];
for (let i = 0; i < subjects.length; i++) {
const tbs = {
version: 'v3',
serialNumber: new BN('01', 16),
signature: {
algorithm: oid.sha256WithRSAEncryption,
parameters: null_
},
issuer: {
type: 'rdnSequence',
value: subjects[i]
},
validity: {
notBefore: { type: 'utcTime', value: now },
notAfter: { type: 'utcTime', value: now + days * 86400000 }
},
subject: {
type: 'rdnSequence',
value: subjects[i]
},
subjectPublicKeyInfo: {
algorithm: {
algorithm: oid.rsaEncryption,
parameters: null_
},
subjectPublicKey: {
unused: 0,
data: publicKey
}
}
};
// Self-sign the certificate.
const tbsDer = rfc5280.TBSCertificate.encode(tbs, 'der');
const signature = crypto.createSign(digest).update(tbsDer).sign(privateKey);
// Construct the signed certificate.
const cert = {
tbsCertificate: tbs,
signatureAlgorithm: {
algorithm: oid.sha256WithRSAEncryption,
parameters: null_
},
signature: {
unused: 0,
data: signature
}
};
// Store the signed certificate.
const pem = rfc5280.Certificate.encode(cert, 'pem', {
label: 'CERTIFICATE'
});
writeFileSync(`./subj-${i}-cert.pem`, `${pem}\n`);
}