Cosign Signature API(json,而不是SOAP)不验证自己创建的签名

时间:2015-02-17 14:20:57

标签: cosign-api

我正在尝试使用Signature API(JSON)签署一个小缓冲区,作为POC集成到我的项目中。我正在使用CoSign Trial开发者帐户服务器。签名已成功创建,但在尝试验证缓冲区时,响应包含以下(不是非常有用)错误:

{u'ErrData': {u'Code': -24,
          u'InnerCode': -1878850959,
          u'Message': u'Failed to verify buffer.',
          u'Module': u'VerifyBuffer'},
 u'Success': False}

我已按照此页面的文档进行操作:

http://docs.arx.com/CoSign_APIs/doc_v7.1/Default.htm#doc_7.1/Verify Buffer.htm#_Toc398808255%3FTocPath%3DCoSign%2520Signature%7CAPI%7CSigning%2520and%2520Verifying%7C_____4

我将我的代码附加在python中(用户名和密码已删除)

import urllib2
import hashlib
import xml.dom.minidom
import base64
import pprint
import json


class Client:
    SIGN_URL = 'https://prime.cosigntrial.com:8081/sapiws/SignBuffer'
    VERIFY_URL = 'https://prime.cosigntrial.com:8081/sapiws/VerifyBuffer'
    GET_CERTS_URL = 'https://prime.cosigntrial.com:8081/sapiws/UserCertificatesGet'
    HEADERS = {'Content-Type': 'application/json; charset=utf-8'}

    def __init__(self, username, password):
        self._username = username
        self._password = password

    def signBytes(self, bytes):
        obj = dict(
            Username=self._username, Password=self._password,
            BufferToSign=base64.b64encode(bytes))
        return self._transaction(obj)

    def verifyBytes(self, bytes, signature):
        obj = dict(
            BufferToSign=base64.b64encode(bytes), Signature=signature)
        return self._transaction(obj, url=self.VERIFY_URL)

    def getCertificates(self):
        return self._transaction(dict(Username=self._username, Password=self._password), url=self.GET_CERTS_URL)

    def signUsingHash(self, bytes):
        digest = hashlib.sha512(bytes).digest()
        obj = dict(
            Username=self._username, Password=self._password,
            BufferToSign=base64.b64encode(digest),
            BufferHash=True, HashAlg="Sha512")
        return self._transaction(obj)

    def verifyUsingHash(self, bytes, signature):
        digest = hashlib.sha512(bytes).digest()
        obj = dict(
            BufferToSign=base64.b64encode(digest), Signature=signature,
            BufferHash=True)
        return self._transaction(obj, url=self.VERIFY_URL)

    def _transaction(self, message, url=SIGN_URL):
        print "Y"*100
        pprint.pprint(message)
        request = urllib2.Request(url, json.dumps(message))
        connection = urllib2.urlopen(request)
        try:
            return json.loads(connection.read())
        finally:
            connection.close()


client = Client(username="", password="")
value = "ABCDEFG"
response1 = client.signBytes(value)
print "X"*100
print response1
verified1 = client.verifyBytes(value, response1[u'Data']    [u'Signature'])
print "Z"*100
pprint.pprint(verified1)

我也尝试过使用BufferHash参数并自己计算哈希值,但也会出现同样的错误。

3 个答案:

答案 0 :(得分:2)

signBuffer函数返回的签名包含\ r \ n字符,在调用verifyBuffer之前从签名中删除这些字符应解决问题。

答案 1 :(得分:2)

要使代码正常运行,您需要做的就是:

  1. 将预定义的请求标头传递给请求本身 -

    urllib2.Request(url, json.dumps(message), self.HEADERS)
    
  2. 请注意,签名的返回base64编码数据包含多余的\ r \ n字符(这是一个已知问题,将在以后的版本中修复)。只需在将数据传递给验证操作之前删除这些字符。例如 -

    client.verifyBytes(value, response1[u'Data'][u'Signature'].replace("\r\n", ""))
    

答案 2 :(得分:2)

感谢Almog和ALX,您的回答很有帮助。不幸的是,我无法提供你的答案,没有足够的stackoverflow声誉。

我已经完成了其他一些细节,比如创建一个pkcs#1签名并验证它。我在这里发布完整的清理源代码,供将来参考。我的结论是,无论使用何种语言,使用REST API的源代码示例都会有所帮助 - 所以我建议在文档站点的示例页面中的某处使用我的一个或者甚至使用我的。

再次感谢您的帮助。

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"