| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
| README_EN.md | ||
kamusm-zd-rs
🇹🇷 Türkçe
An RFC 3161 compliant Kamu SM (Turkish Public CA) timestamp client written in Rust, supporting Kamu SM's custom authentication protocol and compatible with the official Java client.
Table of Contents
- kamusm-zd-rs
Protocol Architecture
Kamu SM timestamp servers use the standard RFC 3161 TimeStampReq/TimeStampResp structure but require a custom identity header for authentication:
- HTTP:
POST /withapplication/timestamp-query - Body: RFC 3161 TimeStampReq (ASN.1 DER)
- Authentication: User authentication via the
identityheader - Response: PKCS#7 SignedData with certificate
Identity Header
identity is the BigInteger hex representation of the DER encoding of the following ASN.1 structure:
ESYAReqEx ::= SEQUENCE {
userid INTEGER,
salt OCTET STRING (16 bytes),
iterationCount INTEGER (100),
iv OCTET STRING (16 bytes, same as salt),
encryptedMessageImprint OCTET STRING
}
Encryption Flow:
- 16-byte random value → used as both salt and IV
- PBKDF2-HMAC-SHA256(password, salt, 100 iterations) → 32-byte AES key
- AES-256-CBC(messageImprint, key, iv) + PKCS#7 padding → encrypted data
- ASN.1 structure → DER encoding → BigInteger → hex string
This prevents replay attacks by using a different salt/IV for each request.
Cryptography References
- RFC 3161: Time-Stamp Protocol (RFC 3161)
- PKCS#7: Public Key Cryptography Standards #7 (RFC 2315)
- PKCS#7 SignedData: Digitally signed data structure (RFC 2315 Section 9.1)
- ASN.1: Abstract Syntax Notation One - Data structure description notation (ITU-T X.680)
- DER: Distinguished Encoding Rules - ASN.1 binary encoding rules (ITU-T X.690)
- PBKDF2: Password-Based Key Derivation Function 2 (RFC 2898 Section 5.2)
- HMAC: Hash-based Message Authentication Code (RFC 2104)
- AES-256: Advanced Encryption Standard, 256-bit key length (FIPS 197)
- CBC: Cipher Block Chaining mode (Wikipedia)
Requirements
- Rust (tested with 1.85)
- Cargo
- A valid Kamu SM user account (customer ID and password)
- Internet connection
Installation
Building from Source
# Clone the repository
git clone https://github.com/omerbustun/kamusm-zd-rs.git
cd kamusm-zd-rs
# Build
cargo build --release
# The executable will be created in target/release/
Running Directly
# Run in debug mode
cargo run -- --help
# Run in release mode
cargo run --release -- --help
Usage
Basic Command Structure
kamusm-zd-rs <COMMAND> [OPTIONS]
Requesting a Timestamp
Timestamp for a file
# SHA256 (recommended/default)
kamusm-zd-rs send \
--host "http://zd.kamusm.gov.tr" \
--customer-id 123 \
--password "password" \
--file document.txt \
--hash sha256
# SHA1
kamusm-zd-rs send \
--host "http://zd.kamusm.gov.tr" \
--customer-id 123 \
--password "password" \
--file document.pdf \
--hash sha1
Timestamp for a hex digest
kamusm-zd-rs send \
--host "http://zd.kamusm.gov.tr" \
--customer-id 123 \
--password "password" \
--digest-hex "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" \
--hash sha256
Checking Credits
kamusm-zd-rs credits \
--host "http://zd.kamusm.gov.tr" \
--customer-id 123 \
--password "password"
Generating an Identity Header
# With a hex digest
kamusm-zd-rs identity \
--customer-id 123 \
--password "password" \
--digest-hex "abc123..."
# With a timestamp (for credit checks)
kamusm-zd-rs identity \
--customer-id 123 \
--password "password" \
--timestamp 1635724800000
Configuration Options
Common Parameters
--host: Kamu SM timestamp server address--customer-id: Customer ID number--password: Customer password--iterations: PBKDF2 iteration count (default: 100)
Send Command Parameters
--file: Path to the file to be timestamped--digest-hex: Hash value directly in hex format--hash: Hash algorithm (sha1orsha256, default:sha256)
Output Files
- File-based operations:
{filename}_zd.der - Hex digest operations:
zd_{timestamp}.der - Output files are in PKCS#7 SignedData format
Technical Implementation
Cryptographic Stack
- Key Derivation: PBKDF2-HMAC-SHA256 (100 iterations, 32-byte key)
- Symmetric Encryption: AES-256-CBC + PKCS#7 padding
- ASN.1 Processing: DER encoding/decoding
- Hash Algorithms: SHA1/SHA256 with OIDs, RFC 3161 compliant
MessageImprint Generation
- Timestamp Request: File/data hash (SHA1/SHA256)
- Credit Check: SHA1(customerID + timestamp_millis)
- Authentication: In all cases, the relevant hash is encrypted and sent in the identity header
Error Handling
Kamu SM returns standard HTTP 200 for errors but includes error messages within the ASN.1 structure.
The client looks for the PKCS#7 SignedData OID (1.2.840.113549.1.7.2):
- Found: Valid timestamp, PKCS#7 is processed
- Not found: ASN.1 is parsed to extract error messages from UTF8String/PrintableString fields
HTTP Request Format
POST / HTTP/1.1
Host: zd.kamusm.gov.tr
Content-Type: application/timestamp-query
User-Agent: kamusm-zd-rs
identity: <hex_encoded_ESYAReqEx>
Cache-Control: no-cache
Pragma: no-cache
Content-Length: <der_length>
<RFC3161_TimeStampReq_DER>
Examples
Successful Timestamp Request
$ kamusm-zd-rs send --host "http://zd.kamusm.gov.tr" --customer-id 123 --password "password" --file test.txt
Response status: 200 OK
Extracted PKCS#7 SignedData saved to test_zd.der
Verification with the Official Client
You can verify timestamps using Kamu SM's official Java console client:
Download: Kamu SM Software Platform - Zamane
$ java -jar tss-client-console-3.1.30.jar -c test.txt test_zd.der
[2025-Sep-27 16:04:45,054 PM] [INFO ] : File timestamp verification will be performed.
[2025-Sep-27 16:04:45,093 PM] [INFO ] : Timestamp is valid, file has not been modified.
Credit Check
$ kamusm-zd-rs credits --host "http://zd.kamusm.gov.tr" --customer-id 123 --password "password"
Response status: 200 OK
Remaining timestamp credits: 847
Error Case
$ kamusm-zd-rs send --host "http://zd.kamusm.gov.tr" --customer-id 999 --password "wrong"
Response status: 200 OK
Error response received (HTTP 200 OK)
Error messages:
User 999 is not known
Common Errors
"Account could not be authenticated"
- Incorrect user password
"User is not known"
- Customer ID not found
- Wrong customer number
Connection errors
- Check the server address
- Check your internet connection
- Check firewall settings
Implementation Notes
Dependencies
- yasna: ASN.1 DER encoding/decoding (ESYAReqEx, TimeStampReq generation)
- aes + cbc: AES-256-CBC implementation (identity encryption)
- pbkdf2 + hmac: Key derivation (PBKDF2-HMAC-SHA256)
- reqwest: HTTP client (rustls-tls backend, suitable for blocking support/async wrapper)
- num-bigint: Java BigInteger.toString(16) compatibility