1

oAuth と二足認証を使用して、Xero API のラッパーを作成しています。これは、Xero が呼ぶ「プライベート」アプリケーションであり、RSA-SHA1 署名が必要です。Coldfusion oAuth ラッパーには、RSA-SHA1 で暗号化する機能がなく、HMAC-SHA1 のみです。CF9にいます。

その結果、GET リクエストの実行中に、次のエラーが発生します。

signature_method_rejected
Private applications must use the RSA-SHA1 signature method

したがって、GET 呼び出しは機能しているように見えますが、問題は署名メソッドにあります。次のように、誰かが作成したソリューションのように見えると思ったものを見つけました。

<cffunction name="rsa_sha1" returntype="string" access="public" descrition="RSA-SHA1 computation based on supplied private key and 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 to 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 the line below --->
               <cfset sig.initSign(keyFactory.getInstance("RSA").generatePrivate(keySpec.init(keyBytes)))> 
               <cfset sig.update(jMsg)>
               <cfset signBytes = sig.sign()>

               <cfreturn ToBase64(signBytes)>
         </cffunction>

次の引数を受け取ります。

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 

ただし、これにより次のエラーが発生します。

Could not read BER data.(ASN1Lengths.determineLengthLen: length greater than 0x7FFF,FFFF.)

ColdFusion cannot determine the line of the template that caused this error. This is often caused by an error in the exception handling subsystem. 

誰でもこれに光を当てることができますか?

編集 - -

ここに画像の説明を入力

私が行った公開証明書をアップロードするためのリンクがあります。また、「プライベート アプリケーションの場合、コンシューマ トークンとシークレットはアクセス トークンとシークレットとしても使用されることに注意してください。」というメモもあります。したがって、リクエストに署名するには、そこに表示されている「コンシューマー シークレット」の値が必要であると想定しています。その場合、その秘密鍵の値を署名用の RSA-SH1 形式に変換するにはどうすればよいですか?

4

1 に答える 1

1

(コメントからの要約)

APIによると、プライベートアプリケーションはRSAパブリック/プライベートペア(1回限りのイベント)を生成する必要があります。次に、公開証明書をサーバーにアップロードし、秘密鍵を使用してRSA-SHA1を使用してすべての要求に署名します。リンクの指示に従った場合、秘密鍵はPEM形式になります。これは、base64でエンコードされたキー値であり、BEGIN/ENDラッパーで囲まれています。

    -----BEGIN RSA PRIVATE KEY-----
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    ....
    -----END RSA PRIVATE KEY-----

でキーを使用する前に、ラッパー間の部分を抽出する必要がありますPKCS8EncodedKeySpec。これを行うには、少なくとも3つの方法があります。最も簡単なオプションは、文字列関数を使用することです。

    // read in the  key file and remove the 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" );

もう1つのオプションは、BouncyCastlePEMReaderクラスを使用することです。それはあなたのためにそれをすべて行います(そしてパスワードで保護されたキーもサポートします)。

    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" );

さらに別のオプションは、opensslを使用してキーをDER形式に変換することです。

    $ 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");

実際の秘密鍵をここ(または別のフォーラム)に投稿すると、危険にさらされます。したがって、新しいキーを生成することを強くお勧めします。

于 2012-06-11T02:31:00.540 に答える