ColdFusion oAuth RSA-SHA1 authorisation for Xero wrapper -
i'm writing wrapper xero api, using oauth , two-legged authentication. "private" application, xero calls it, requires rsa-sha1 signature. coldfusion oauth wrapper doesn't have function encrypting in rsa-sha1, hmac-sha1. on cf9.
consequently, in course of running request, following error:
signature_method_rejected private applications must use rsa-sha1 signature method
so, looks call working, issue signature method. found thought looked solution created, follows:
<cffunction name="rsa_sha1" returntype="string" access="public" descrition="rsa-sha1 computation based on supplied private key , supplied base signature string."> <cfargument name="signkey" type="string" required="true" hint="base64 formatted pkcs8 private key"> <cfargument name="signmessage" type="string" required="true" hint="msg sign"> <cfargument name="sformat" type="string" required="false" default="utf-8"> <cfset var jkey = javacast("string", arguments.signkey)> <cfset var jmsg = javacast("string",arguments.signmessage).getbytes(arguments.sformat)> <cfset var key = createobject("java", "java.security.privatekey")> <cfset var keyspec = createobject("java","java.security.spec.pkcs8encodedkeyspec")> <cfset var keyfactory = createobject("java","java.security.keyfactory")> <cfset var b64dec = createobject("java", "sun.misc.base64decoder")> <cfset var sig = createobject("java", "java.security.signature")> <cfset var byteclass = createobject("java", "java.lang.class")> <cfset var bytearray = createobject("java","java.lang.reflect.array")> <cfset byteclass = byteclass.forname(javacast("string","java.lang.byte"))> <cfset keybytes = bytearray.newinstance(byteclass, javacast("int","1024"))> <cfset keybytes = b64dec.decodebuffer(jkey)> <!--- keybytes = 48-111-10345-125-5349-114-581835-28-330-3984120-2848-4384-1-43 ---> <cfset sig = sig.getinstance("sha1withrsa", "sunjsse")> <!--- error occurs on line below ---> <cfset sig.initsign(keyfactory.getinstance("rsa").generateprivate(keyspec.init(keybytes)))> <cfset sig.update(jmsg)> <cfset signbytes = sig.sign()> <cfreturn tobase64(signbytes)> </cffunction>
it receives following arguments:
sformat utf-8 signkey 0jxxxxxxxxxxxxxxxxxxxp& signmessage get&https%3a%2f%2fapi.xero.com%2fapi.xro%2f2.0%2fcontacts&contactid%3d%26contactnumber%3d%26name%3d7-eleven%26oauth_consumer_key%3dxxxxxxxxxxxxxxxx%26oauth_nonce%3dxxxxxxxxxxxxxxxx%26oauth_signature_method%3drsa-sha1%26oauth_timestamp%3d1339055484%26oauth_version%3d1.0
however, produces following error:
could not read ber data.(asn1lengths.determinelengthlen: length greater 0x7fff,ffff.) coldfusion cannot determine line of template caused error. caused error in exception handling subsystem.
can shed light on this?
edit ----
there link uploading public cert, did. there note saying: "note, private applications, consumer token , secret used access token , secret.". assuming need "consumer secret" value shown there in order sign request. being case, how convert secret key value rsa-sh1 format signature?
(summary comments)
according their api private applications must generate rsa public/private pair (one time event). upload public certificate server, , use private key sign requests using rsa-sha1. if followed instructions in link private key in pem
format, key value encoded in base64, enclosed within begin/end wrapper:
-----begin rsa private key----- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx .... -----end rsa private key-----
you need extract portion between wrapper before using key pkcs8encodedkeyspec
. there @ least 3 ways that. simplest option use string functions:
// read in key file , remove wrapper pathtokey = "c:/path/to/file/privatekey.pem"; rawkey = fileread( pathtokey ); rawkey = replace( rawkey, "-----begin rsa private key-----"& chr(10), "" ); rawkey = replace( rawkey, "-----end rsa private key-----", "" ); yourmessage = "get&https%3a%2f%2fapi.xero.com%2fapi.xro%2f2.0%2f..."; signature = rsa_sha1( rawkey, yourmessage, "utf-8" );
another option use bouncycastle pemreader class. (and supports password protected keys).
pathtokey = "c:/path/to/file/privatekey.pem"; provider = createobject("java", "org.bouncycastle.jce.provider.bouncycastleprovider").init(); security = createobject("java", "java.security.security").addprovider( provider ); filereader = createobject("java", "java.io.filereader").init( pathtokey ); keyreader = createobject("java", "org.bouncycastle.openssl.pemreader").init( filereader); privatekey = keyreader.readobject().getprivate(); rawkey = binaryencode( privatekey.getencoded(), "base64" ); yourmessage = "get&https%3a%2f%2fapi.xero.com%2fapi.xro%2f2.0%2fcontacts&...."; signature = rsa_sha1( rawkey, yourmessage, "utf-8" );
yet option convert key der format openssl
$ openssl pkcs8 -topk8 -in privatekey.pem -outform der -nocrypt -out privatekey.pk8 pathtokey = "c:/path/to/file/privatekey.pk8"; bytes = binaryencode( filereadbinary(pathtokey), "base64"); yourmessage = "get&https%3a%2f%2fapi.xero.com%2fapi.xro%2f2.0%2f..."; signature = rsa_sha1(rawkey, testmessage, "utf-8");
note if posted actual private key here (or on forum), compromised. recommend generating new keys.
Comments
Post a Comment