Skip to content

Instantly share code, notes, and snippets.

@rfde
Last active December 4, 2017 17:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rfde/ea6c255b75863ff0632b1994ddae956a to your computer and use it in GitHub Desktop.
Save rfde/ea6c255b75863ff0632b1994ddae956a to your computer and use it in GitHub Desktop.
Proof of concept: python script to obtain a trusted time stamp from a public time stamp server (rfc3161, e.g. zeitstempel.dfn.de or tsa.safecreative.org)
#!/usr/bin/env python3
#### TODO: Flexibilität: https://docs.python.org/3.3/library/argparse.html#argparse.ArgumentParser.add_argument
import random
import hashlib
import urllib.request
import logging
from subprocess import call
from pyasn1.type import univ, namedtype, namedval, tag
from pyasn1.codec.der import encoder as der_encoder
# log "info" messages to stdout, include date/time
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S', level=logging.INFO)
#####################################################################
# ASN.1 definitions from RFC3161 and RFC5912
#
# TimeStampReq ::= SEQUENCE {
# version INTEGER { v1(1) },
# messageImprint MessageImprint,
# --a hash algorithm OID and the hash value of the data to be
# --time-stamped
# reqPolicy TSAPolicyId OPTIONAL,
# nonce INTEGER OPTIONAL,
# certReq BOOLEAN DEFAULT FALSE,
# extensions [0] IMPLICIT Extensions OPTIONAL }
#
# MessageImprint ::= SEQUENCE {
# hashAlgorithm AlgorithmIdentifier,
# hashedMessage OCTET STRING }
#
# TSAPolicyId ::= OBJECT IDENTIFIER
#
# AlgorithmIdentifier ::= SEQUENCE {
# algorithm OBJECT IDENTIFIER,
# parameters ANY DEFINED BY algorithm OPTIONAL }
#
# id-sha512 OBJECT IDENTIFIER ::= {
# joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
# csor(3) nistalgorithm(4) hashalgs(2) 3 }
#####################################################################
# ASN.1: classes
class AlgorithmIdentifier(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('algorithm', univ.ObjectIdentifier()),
namedtype.OptionalNamedType('parameters', univ.Any())
)
class MessageImprint(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('hashAlgorithm', AlgorithmIdentifier()),
namedtype.NamedType('hashedMessage', univ.OctetString())
)
class TimeStampReq(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('version', univ.Integer()),
namedtype.NamedType('messageImprint', MessageImprint()),
namedtype.OptionalNamedType('reqPolicy', univ.ObjectIdentifier()),
namedtype.OptionalNamedType('nonce', univ.Integer()),
namedtype.DefaultedNamedType('certReq', univ.Boolean(False))
# namedtype.OptionalNamedType('extensions', Extensions())
)
## Frist step: generate SHA512 hash from given file
hasher = hashlib.sha512()
with open('blank.pdf', 'rb') as f:
buf = f.read()
hasher.update(buf)
logging.info("File hash: " + hasher.hexdigest().upper())
filehash = hasher.digest()
## Second step: assemble TimeStampRequest (ASN.1 Sequence) locally
myRequest = TimeStampReq()
myRequest['version'] = univ.Integer(1) # Version: always 1
myRequest['messageImprint'] = MessageImprint()
myRequest['messageImprint']['hashAlgorithm'] = AlgorithmIdentifier()
myRequest['messageImprint']['hashAlgorithm']['algorithm'] = univ.ObjectIdentifier((2, 16, 840, 1, 101, 3, 4, 2, 3)) # Algorithm = sha512 (constant)
myRequest['messageImprint']['hashedMessage'] = filehash # the actual sha512 hash
myRequest['nonce'] = random.getrandbits(64) # Nonce: 64bit random integer
logging.info('My nonce: ' + hex(myRequest['nonce']))
myRequest['certReq'] = univ.Boolean(True)
# encode request in DER format
binRequest = der_encoder.encode(myRequest)
# save request to file
with open('a.tsq', 'wb') as f:
f.write(binRequest)
logging.info("Wrote request to file: " + "a.tsq")
# call openssl to display the request
print("-- OpenSSL --")
call(["openssl", "ts", "-query", "-in", "./a.tsq", "-text"])
# Read request from file
# binRequest = None
# with open("a.tsq", "rb") as f:
# binRequest = bytearray(f.read())
## Third step: Request Timestamp from server
# assemble HTTP POST request
postRequest = urllib.request.Request(
url="http://tsa.safecreative.org",
data=binRequest, # encoded TimeStampReq
headers={"Content-Type" : "application/timestamp-query"},
method="POST"
)
# send HTTP POST request to request time stamp
with urllib.request.urlopen(postRequest) as response:
# write response to file
with open("resp.tsr", "wb") as f:
f.write(response.read())
logging.info("Wrote response to file: " + "resp.tsr")
# call openssl to display the response
print("-- OpenSSL --")
call(["openssl", "ts", "-reply", "-in", "./resp.tsr", "-text"])
logging.info("Done.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment