From dc218d8e40c969b7759c6a0915abfd3c163ab1b5 Mon Sep 17 00:00:00 2001 From: Michael Gebetsroither Date: Wed, 3 Oct 2012 14:37:32 +0200 Subject: [PATCH 1/3] add support for http basic auth --- rfc3161/api.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rfc3161/api.py b/rfc3161/api.py index b430fb2..c9ee9bd 100644 --- a/rfc3161/api.py +++ b/rfc3161/api.py @@ -7,6 +7,7 @@ import M2Crypto.X509 as X509 import rfc3161 import hashlib import urllib2 +import base64 __all__ = ('RemoteTimestamper','check_timestamp') @@ -86,11 +87,13 @@ def check_timestamp(tst, certificate, data=None, sha1=None): class RemoteTimestamper(object): - def __init__(self, url, certificate=None, capath=None, cafile=None): + def __init__(self, url, certificate=None, capath=None, cafile=None, username=None, password=None): self.url = url self.certificate = certificate self.capath = capath self.cafile = cafile + self.username = username + self.password = password def check_response(self, response, digest): ''' @@ -118,6 +121,9 @@ class RemoteTimestamper(object): binary_request = encoder.encode(request) http_request = urllib2.Request(self.url, binary_request, { 'Content-Type': 'application/timestamp-query' }) + if self.username != None: + base64string = base64.standard_b64encode('%s:%s' % (self.username, self.password)) + http_request.add_header("Authorization", "Basic %s" % base64string) response = urllib2.urlopen(http_request).read() # open('response.tsr', 'w').write(response) tst_response, substrate = decoder.decode(response, asn1Spec=rfc3161.TimeStampResp()) From aafb4124876f27dfaa3cead3ac643a5956cabd3b Mon Sep 17 00:00:00 2001 From: Michael Gebetsroither Date: Wed, 3 Oct 2012 15:46:27 +0200 Subject: [PATCH 2/3] let openssl figure out certificate format background: common converted pkcs#12 certificates from openssl do not start with string '-----' because they include a 'Bag Attributes' header --- rfc3161/api.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rfc3161/api.py b/rfc3161/api.py index c9ee9bd..ebc3361 100644 --- a/rfc3161/api.py +++ b/rfc3161/api.py @@ -26,10 +26,11 @@ def check_timestamp(tst, certificate, data=None, sha1=None): if substrate: return False, "extra data after tst" signed_data = tst.content - if certificate.startswith('-----'): - certificate = X509.load_cert_string(certificate, X509.FORMAT_PEM) - elif certificate: - certificate = X509.load_cert_string(certificate, X509.FORMAT_DER) + if certificate != "": + try: + certificate = X509.load_cert_string(certificate, X509.FORMAT_PEM) + except: + certificate = X509.load_cert_string(certificate, X509.FORMAT_DER) else: return False, "missing certificate" # check message imprint with respect to locally computed digest From 5dc67b1ee0c6efa02aea25b3f72751a196e81a6b Mon Sep 17 00:00:00 2001 From: Michael Gebetsroither Date: Wed, 3 Oct 2012 16:45:20 +0200 Subject: [PATCH 3/3] add support for sha256, sha384 and sha512 --- rfc3161/api.py | 25 ++++++++++++++++--------- rfc3161/constants.py | 5 ++++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/rfc3161/api.py b/rfc3161/api.py index ebc3361..b93b36a 100644 --- a/rfc3161/api.py +++ b/rfc3161/api.py @@ -9,15 +9,20 @@ import hashlib import urllib2 import base64 -__all__ = ('RemoteTimestamper','check_timestamp') +__all__ = ('RemoteTimestamper','check_timestamp','get_hash_oid') id_attribute_messageDigest = univ.ObjectIdentifier((1,2,840,113549,1,9,4,)) -def check_timestamp(tst, certificate, data=None, sha1=None): +def get_hash_oid(hashname): + return rfc3161.__dict__['id_'+hashname] + +def check_timestamp(tst, certificate, data=None, sha1=None, hashname=None): + hashobj = hashlib.new(hashname or 'sha1') if not sha1: if not data: raise ValueError("check_timestamp requires data or sha1 argument") - digest = hashlib.sha1(data).digest() + hashobj.update(data) + digest = hashobj.digest() else: digest = sha1 @@ -35,7 +40,7 @@ def check_timestamp(tst, certificate, data=None, sha1=None): return False, "missing certificate" # check message imprint with respect to locally computed digest message_imprint = tst.tst_info.message_imprint - if message_imprint.hash_algorithm[0] != rfc3161.id_sha1 or \ + if message_imprint.hash_algorithm[0] != get_hash_oid(hashobj.name) or \ str(message_imprint.hashed_message) != digest: return False, 'Message imprint mismatch' # @@ -88,30 +93,32 @@ def check_timestamp(tst, certificate, data=None, sha1=None): class RemoteTimestamper(object): - def __init__(self, url, certificate=None, capath=None, cafile=None, username=None, password=None): + def __init__(self, url, certificate=None, capath=None, cafile=None, username=None, password=None, hashname=None): self.url = url self.certificate = certificate self.capath = capath self.cafile = cafile self.username = username self.password = password + self.hashobj = hashlib.new(hashname or 'sha1') def check_response(self, response, digest): ''' Check validity of a TimeStampResponse ''' tst = response.time_stamp_token - return check_timestamp(tst, sha1=digest, certificate=self.certificate) + return check_timestamp(tst, sha1=digest, certificate=self.certificate, hashname=self.hashobj.name) def __call__(self, data=None, sha1=None): algorithm_identifier = rfc2459.AlgorithmIdentifier() - algorithm_identifier.setComponentByPosition(0, rfc3161.id_sha1) + algorithm_identifier.setComponentByPosition(0, get_hash_oid(self.hashobj.name)) message_imprint = rfc3161.MessageImprint() message_imprint.setComponentByPosition(0, algorithm_identifier) if data: - sha1 = hashlib.sha1(data).digest() + self.hashobj.update(data) + sha1 = self.hashobj.digest() elif sha1: - assert len(sha1) == 20 + assert len(sha1) == self.hashobj.digest_size else: raise ValueError('You must pass some data to digest, or the sha1 digest') message_imprint.setComponentByPosition(1, sha1) diff --git a/rfc3161/constants.py b/rfc3161/constants.py index 8d0f8c1..d0d7663 100644 --- a/rfc3161/constants.py +++ b/rfc3161/constants.py @@ -1,7 +1,10 @@ from pyasn1.type import univ -__all__ = ('id_kp_timeStamping','id_sha1', 'id_ct_TSTInfo',) +__all__ = ('id_kp_timeStamping','id_sha1', 'id_sha256', 'id_sha384', 'id_sha512', 'id_ct_TSTInfo',) id_kp_timeStamping = univ.ObjectIdentifier((1,3,6,1,5,5,7,3,8)) id_sha1 = univ.ObjectIdentifier((1,3,14,3,2,26)) +id_sha256 = univ.ObjectIdentifier((2,16,840,1,101,3,4,2,1,)) +id_sha384 = univ.ObjectIdentifier((2,16,840,1,101,3,4,2,2,)) +id_sha512 = univ.ObjectIdentifier((2,16,840,1,101,3,4,2,3,)) id_ct_TSTInfo = univ.ObjectIdentifier((1,2,840,113549,1,9,16,1,4))