Thanks Almog and ALX, your answers helped. Unfortunately, i can't upvote your answers, don't have enough stackoverflow reputation.
I've managed my way around few other details, like creating a pkcs#1 signature and verifying it. I'm posting here the full cleaned up source code for future reference for others. My conclusion is that a source code example of using the REST API would have really helped, no matter the language - so i suggest writing one or even using mine, somewhere in the examples page in the documentation site.
Thanks again for your help.
import urllib2
import hashlib
import base64
import json
import string
class Client:
_HEADERS = {'Content-Type': 'application/json; charset=utf-8'}
_ALGORITHMS = dict(
Sha256=lambda x: hashlib.sha256(x).digest(),
Sha384=lambda x: hashlib.sha385(x).digest(),
Sha512=lambda x: hashlib.sha512(x).digest())
_PKCS1_FLAGS = 0x80000
_ALGORITHM_FLAGS = dict(
Sha256=0x04000,
Sha384=0x08000,
Sha512=0x10000)
def __init__(self, username, password, hostname="prime.cosigntrial.com"):
self._username = username
self._password = password
self._signURL = 'https://%s:8081/sapiws/SignBuffer' % hostname
self._verifyURL = 'https://%s:8081/sapiws/VerifyBuffer' % hostname
self._getCertificatesURL = 'https://%s:8081/sapiws/UserCertificatesGet' % hostname
self._serverInfoURL = 'https://%s:8081/sapiws/ServerInfoGet' % hostname
def signBytes(self, bytes, algorithm="Sha512", pkcs1=False):
assert algorithm in self._ALGORITHMS, "'%s' is not Sha256|384|512" % algorithm
parameters = dict(
Username=self._username, Password=self._password,
BufferToSign=base64.b64encode(bytes), HashAlg=algorithm)
if pkcs1:
parameters['Flags'] = self._PKCS1_FLAGS
result = self._transaction(self._signURL, parameters)
if not result[u'Success']:
raise Exception("Sign buffer failed (%s)" % result)
return result[u'Data'][u'Signature']
def verifyBytes(self, bytes, signature, pkcs1Certificate=None, pkcs1Algorithm="Sha512"):
assert self._isBase64(signature), "Signature must be in base64 format"
parameters = dict(
BufferToSign=base64.b64encode(bytes), Signature=self._removeCRLF(signature))
if pkcs1Certificate is not None:
assert self._isBase64(pkcs1Certificate), "Certificate must be in base 64 format"
assert pkcs1Algorithm in self._ALGORITHM_FLAGS, "'%s' is no Sha256|384|512" % pkcs1Algorithm
parameters['Flags'] = self._PKCS1_FLAGS | self._ALGORITHM_FLAGS[pkcs1Algorithm]
parameters['Certificate'] = self._removeCRLF(pkcs1Certificate)
result = self._transaction(self._verifyURL, parameters)
if not result[u'Success']:
raise Exception("Verify buffer failed (%s)" % result)
return result[u'Data']
def signUsingHash(self, bytes, algorithm="Sha512", pkcs1=False):
assert algorithm in self._ALGORITHMS, "'%s' is not Sha256|384|512" % algorithm
digest = self._ALGORITHMS[algorithm](bytes)
parameters = dict(
Username=self._username, Password=self._password,
BufferToSign=base64.b64encode(digest),
BufferHash=True, HashAlg=algorithm)
if pkcs1:
parameters['Flags'] = self._PKCS1_FLAGS
result = self._transaction(self._signURL, parameters)
if not result[u'Success']:
raise Exception("Sign buffer failed (%s)" % result)
return result[u'Data'][u'Signature']
def verifyUsingHash(self, bytes, signature, algorithm="Sha512", pkcs1Certificate=None):
assert self._isBase64(signature), "Signature must be in base64 format"
assert algorithm in self._ALGORITHMS, "'%s' is not Sha256|384|512" % algorithm
digest = self._ALGORITHMS[algorithm](bytes)
parameters = dict(
BufferToSign=base64.b64encode(digest), Signature=self._removeCRLF(signature),
BufferHash=True)
if pkcs1Certificate is not None:
assert self._isBase64(pkcs1Certificate), "Certificate must be in base 64 format"
parameters['Flags'] = self._PKCS1_FLAGS
parameters['Certificate'] = self._removeCRLF(pkcs1Certificate)
result = self._transaction(self._verifyURL, parameters)
if not result[u'Success']:
raise Exception("Verify buffer failed (%s)" % result)
return result[u'Data']
def getCertificates(self):
result = self._transaction(
self._getCertificatesURL,
dict(Username=self._username, Password=self._password))
if not result[u'Success']:
raise Exception("Getting certificates failed (%s)" % result)
return result[u'Data'][u'Certificates']
def serverInfo(self):
result = self._transaction(self._serverInfoURL, {})
if not result[u'Success']:
raise Exception("Getting server info failed (%s)" % result)
return result[u'Data']
def _transaction(self, url, parameters):
request = urllib2.Request(url, json.dumps(parameters), self._HEADERS)
connection = urllib2.urlopen(request)
try:
return json.loads(connection.read())
finally:
connection.close()
def _isBase64(self, data):
valid = string.lowercase + string.uppercase + string.digits + "+/=\r\n"
return [x for x in data if x not in valid] == []
def _removeCRLF(self, s):
return s.replace("\r\n", "")
if __name__ == "__main__":
import pprint
USERNAME = "" # fill this
PASSWORD = "" # fill this
VALUE = "ABCDEFG"
client = Client(username=USERNAME, password=PASSWORD)
print "SERVER INFO:"
pprint.pprint(client.serverInfo())
print "USER CERTIFICATES:"
certificates = client.getCertificates()
pprint.pprint(certificates)
firstCertificate = certificates[0]['Certificate']
print "Signing bytes using pkcs#7:"
signedWith7 = client.signBytes(VALUE)
print "Signing bytes using pkcs#1:"
signedWith1 = client.signBytes(VALUE, pkcs1=True)
print "Signing hash using pkcs#7:"
signedHashWith7 = client.signUsingHash(VALUE)
print "Signing hash using pkcs#1:"
signedHashWith1 = client.signUsingHash(VALUE, pkcs1=True)
assert signedWith1 == signedHashWith1, \
"Expected signature from hash to be equals to be identical"
print "Verify bytes using pkcs#7:"
result = client.verifyBytes(VALUE, signedWith7)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "Verify bytes using pkcs#1:"
result = client.verifyBytes(VALUE, signedWith1, pkcs1Certificate=firstCertificate)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "Verify hash using pkcs#7:"
result = client.verifyUsingHash(VALUE, signedWith7)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "Verify hash, using hash signature, using pkcs#7:"
result = client.verifyUsingHash(VALUE, signedHashWith7)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "Verify hash using pkcs#1:"
result = client.verifyUsingHash(VALUE, signedWith1, pkcs1Certificate=firstCertificate)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "All tests passed"