Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 240
28 changes: 0 additions & 28 deletions .eslintrc.json

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/yarn-vitest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
node-version: '22'
cache: 'yarn'
- run: yarn install --frozen-lockfile
- run: yarn test
Expand Down
23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
Timestamp
=============
# Timestamp

Trustedtimestamp service implements the generate and verification of timestamps.

* [Install](#install)
* [Usage](#usage)
* [Params](#params)
* [Default config](#default-config)
* [Config provider options](#config-provider-options)
* [Required fields](#required-fields)
* [Optional fields](#optional-fields)
* [Config example](#config-example)
* [Public methods](#public-methods)

- [Timestamp](#timestamp)
- [Install](#install)
- [Usage](#usage)
- [Params](#params)
- [Default config](#default-config)
- [Config provider options](#config-provider-options)
- [Required fields](#required-fields)
- [Optional fields](#optional-fields)
- [Config example](#config-example)
- [Public methods](#public-methods)

## Install

Expand Down
54 changes: 54 additions & 0 deletions app/cjs/app/createTimestamp.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const path = require('path')
const { TrustedTimestampService: TrustedTimestampServiceLib, CreateTimestampTokenError } = require('@techteamer/timestamp')

const certPath = path.join(__dirname, '..', '..', 'cert');

const config = {
certsLocation: certPath,
providers: [
{
name: 'bteszt',
url: 'http://wiremock:8080/tsa',
auth: {
user: 'username',
pass: 'password'
},
proxy: {
url: 'http://localhost:8080'
}
}
]
}

async function createTimestampToken () {
const trustedTimestampServiceInstance = new TrustedTimestampServiceLib('normal', config)
const digest = 'ca447095370ccb6f66157119a7dd100ee889a7c6baf69a52b37d0c4040c19e68'
const hashAlgorithm = 'sha256'
const dataSize = 20

try {
const { timestamp, providerName } = await trustedTimestampServiceInstance.createTimestampToken(
digest,
hashAlgorithm,
dataSize
)
console.info({ timestamp, providerName })
} catch (err) {
if (err instanceof CreateTimestampTokenError) {
const { providerName, logHistory } = err.context

console.error(
'Failed to create trusted timestamp.',
`Provider: ${providerName},`,
`history: ${JSON.stringify(logHistory, null, 2)}`
)
}

console.error('Failed to create trusted timestamp', err)
throw new Error('Failed to create trusted timestamp')
}


}

createTimestampToken()
12 changes: 12 additions & 0 deletions app/cjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "cjs",
"version": "1.0.0",
"main": "test/index.js",
"license": "MIT",
"scripts": {
"start": "node app/createTimestamp.test.js"
},
"dependencies": {
"@techteamer/timestamp": "file:../../package/timestamp_service"
}
}
18 changes: 18 additions & 0 deletions app/forge/digest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const fs = require('fs');
const crypto = require('crypto');

const filePath = 'test.txt'; // vagy bármilyen másik fájl

const data = fs.readFileSync(filePath);

// SHA256 digest
const hash = crypto.createHash('sha256');
hash.update(data);
const digestHex = hash.digest('hex');

// Méret
const fileSize = data.length;

console.log(`Fájl: ${filePath}`);
console.log(`Méret: ${fileSize} byte`);
console.log(`SHA256 digest: ${digestHex}`);
Binary file added app/forge/mock_response.tsr
Binary file not shown.
10 changes: 10 additions & 0 deletions app/forge/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "forge",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"asn1.js": "^5.4.1",
"node-forge": "^1.3.1"
}
}
Binary file added app/forge/request.tsq
Binary file not shown.
1 change: 1 addition & 0 deletions app/forge/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Timestamp test file
85 changes: 85 additions & 0 deletions app/forge/tsa_mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const forge = require('node-forge');
const fs = require('fs');

// Kulcs + tanúsítvány generálása
function generateKeyAndCert() {
return new Promise((resolve, reject) => {
forge.pki.rsa.generateKeyPair({ bits: 2048, workers: 2 }, (err, keypair) => {
if (err) return reject(err);

const cert = forge.pki.createCertificate();
cert.publicKey = keypair.publicKey;
cert.serialNumber = (Math.floor(Math.random() * 1e9)).toString();
const now = new Date();
cert.validity.notBefore = new Date(now.getTime() - 24 * 60 * 60 * 1000);
cert.validity.notAfter = new Date(now.getTime() + 365 * 24 * 60 * 60 * 1000);

const attrs = [{ name: 'commonName', value: 'Mock TSA' }];
cert.setSubject(attrs);
cert.setIssuer(attrs);

cert.setExtensions([
{ name: 'basicConstraints', cA: false, critical: true },
{ name: 'keyUsage', digitalSignature: true, nonRepudiation: true },
{
name: 'extKeyUsage',
timeStamping: true, // <- fontos!
critical: true,
},
{ name: 'subjectKeyIdentifier' }
]);

cert.sign(keypair.privateKey, forge.md.sha256.create());

resolve({ keypair, cert });
});
});
}

// Mock TSR (egyszerű JSON base64 aláírással)
function createMockTSR(cert, privateKey, dataBytes) {
const md = forge.md.sha256.create();
md.update(dataBytes.toString('binary'));

const signature = privateKey.sign(md);

const mockTSR = {
cert: forge.pki.certificateToPem(cert),
signature: forge.util.encode64(signature),
};

return Buffer.from(JSON.stringify(mockTSR));
}

async function main() {
if (process.argv.length < 3) {
console.log('Usage: node tsa_mock.js <file_to_timestamp>');
process.exit(1);
}

const inputFile = process.argv[2];
const dataBytes = fs.readFileSync(inputFile);

const { keypair, cert } = await generateKeyAndCert();

// Mentés PEM fájlokba
const certPem = forge.pki.certificateToPem(cert);
const keyPem = forge.pki.privateKeyToPem(keypair.privateKey);

fs.writeFileSync('tsa.crt.pem', certPem);
fs.writeFileSync('tsa.key.pem', keyPem);

console.log('\n=== Tanúsítvány (tsa.crt.pem) ===\n');
console.log(certPem);

console.log('\n=== Privát kulcs (tsa.key.pem) ===\n');
console.log(keyPem);

// Mock TSR létrehozása
const tsr = createMockTSR(cert, keypair.privateKey, dataBytes);
fs.writeFileSync('response.tsr', tsr);

console.log('\n✅ Mock timestamp response elmentve: response.tsr');
}

main().catch(console.error);
28 changes: 28 additions & 0 deletions app/forge/tsa_openssl.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = ext

[ dn ]
CN = Dummy TSA

[ ext ]
basicConstraints = critical,CA:FALSE
keyUsage = digitalSignature, nonRepudiation
extendedKeyUsage = timeStamping
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer

[ tsa ]
default_tsa = tsa_config1

[ tsa_config1 ]
serial = tsa/serial
signer_cert = tsa.crt.pem
certs = tsa.crt.pem
signer_key = tsa.key.pem
digest = sha256
policy = 1.2.3.4.1
clock_precision_digits = 2
104 changes: 104 additions & 0 deletions app/forge/tsr-generator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
const fs = require('fs');
const forge = require('node-forge');
const asn1 = forge.asn1;

// --- ADATOK --- //

const sha256OID = '2.16.840.1.101.3.4.2.1'; // SHA-256 OID
const digestHex = 'ca447095370ccb6f66157119a7dd100ee889a7c6baf69a52b37d0c4040c19e68'; // példa digest
const digestBytes = forge.util.hexToBytes(digestHex);

// --- MESSAGE IMPRINT (ASN.1) --- //
const messageImprint = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
// hashAlgorithm SEQUENCE
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
// algorithm OID
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, asn1.oidToDer(sha256OID).getBytes()),
// parameters NULL
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, ''),
]),
// hashedMessage OCTET STRING
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, digestBytes),
]);

// --- TSTInfo (ASN.1) --- //
const tstInfo = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
// version INTEGER (1)
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, String.fromCharCode(1)),
// policy OBJECT IDENTIFIER (példa OID)
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, asn1.oidToDer('1.2.3.4.1').getBytes()),
// messageImprint (az előző)
messageImprint,
// serialNumber INTEGER (1)
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, String.fromCharCode(1)),
// genTime GeneralizedTime (most)
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.GENERALIZEDTIME, false, toGeneralizedTime(new Date())),
]);

// DER kódolás
const tstInfoDer = asn1.toDer(tstInfo).getBytes();

// --- SIGNED DATA (PKCS7) --- //

const privateKeyPem = fs.readFileSync('./tsa.key.pem', 'utf8');
const certPem = fs.readFileSync('./tsa.crt.pem', 'utf8');

const p7 = forge.pkcs7.createSignedData();

// A TSTInfo DER bufferét kell tartalomként adni, az ASN.1 Bufferből forge Buffer kell
p7.content = forge.util.createBuffer(tstInfoDer);

p7.addCertificate(certPem);
p7.addSigner({
key: forge.pki.privateKeyFromPem(privateKeyPem),
certificate: forge.pki.certificateFromPem(certPem),
digestAlgorithm: forge.pki.oids.sha256,
authenticatedAttributes: [
{
type: forge.pki.oids.contentType,
// id-ct-TSTInfo OID, string formában
value: '1.2.840.113549.1.9.16.1.4',
},
{
type: forge.pki.oids.messageDigest,
value: forge.md.sha256.create().update(tstInfoDer).digest().getBytes(),
},
{
type: forge.pki.oids.signingTime,
value: new Date(),
},
],
});
p7.sign();

// PKIStatusInfo ASN.1 objektum (status = 0)
const status = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, String.fromCharCode(0)), // status = granted
// opcionális mezők: statusString, failInfo itt kihagyva
]);

// TimeStampToken (PKCS7) ASN.1 objektum
const timeStampTokenAsn1 = p7.toAsn1();

// TimeStampResp ::= SEQUENCE { status PKIStatusInfo, timeStampToken TimeStampToken }
const tsResp = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
status,
timeStampTokenAsn1,
]);

// DER kódolás és fájlba írás
const tsRespDerBytes = asn1.toDer(tsResp).getBytes();
fs.writeFileSync('mock_response.tsr', Buffer.from(tsRespDerBytes, 'binary'));

console.log('✅ mock_response.tsr elkészült!');

function toGeneralizedTime(date) {
function pad(n) { return n < 10 ? '0' + n : n; }
return date.getUTCFullYear().toString() +
pad(date.getUTCMonth() + 1) +
pad(date.getUTCDate()) +
pad(date.getUTCHours()) +
pad(date.getUTCMinutes()) +
pad(date.getUTCSeconds()) +
'Z';
}
Loading
Loading