-1

アップデート

この質問がまだ注目を集めていることに気づきませんでした。

少し前に問題を見つけて修正しましたが、基本的には、物事を適切に行う方法を理解していませんでした。証明書に適切なファイル タイプを使用していなかった、秘密鍵を適切に読み取っていなかった (PEM_read_RSAPrivateKeyではなくを使用する必要がPEM_read_PrivateKeyあった)、署名を適切に計算していなかった、など。

それを理解するのに必要以上に時間がかかりました。

時間を割いて回答してくださった皆様、ありがとうございました。

オリジナル

いくつかの要求にデジタル署名するためのコードに取り組んでいますが、コードから生成している署名が正しくなく、コマンド ラインから生成された署名と一致しません。問題は、秘密鍵を適切に読み取っていないことだと思いますがその場合はエラーが返されると予想されますが、そうではありません。

私がopensslを扱うのはこれが初めてで、間違ったことをしていると確信していますが、知的な質問をするのに十分な理解はまだありません.

MessageSignerlibcrypto の雑用を処理するクラスを作成しました。秘密鍵と証明書は、クラスの属性です。

class MessageSigner 
{
  ...
  private:

  EVP_PKEY *private_key;
  X509     *certificate;
};

NULLインスタンスの作成時にこれらを初期化します。

MessageSigner::MessageSigner() : 
  private_key( NULL ),
  certificate( NULL )
{
}

次のように秘密鍵をロードします。

void MessageSigner::addKeyFile( const std::string& filename, const std::string& passphrase )
{
  FILE *fp = ::fopen( keyfile.c_str(), "r" );
  if ( !fp )
    // throw exception

  private_key = PEM_read_PrivateKey( fp, NULL, NULL, passphrase.c_str() );
  ::fclose( fp );

  if ( !private_key )
    // throw exception
}

そして、私は署名を次のように生成しています

void MessageSigner::signMessage( const std::vector< unsigned char >& msg, std::vector< unsigned char >& signature )
{
  unsigned char *msgbuf = new unsigned char [msg.size()];
  std::copy( msg.begin(), msg.end(), msgbuf );

  unsigned char *sigbuf;
  size_t sigbuf_length;

  EVP_MD_CTX *ctx = EVP_MT_CTX_create();
  if ( !ctx )
    // throw exception

  if ( EVP_DigestSignInit( ctx, NULL, EVP_sha256(), NULL, private_key ) != 1)
    // throw exception

  if ( EVP_DigestSignUpdate( ctx, msgbuf, msg.size() ) != 1 )
    // throw exception

  if ( EVP_DigestSignFinal( ctx, NULL, &sigbuf_length ) != 1 )
    // throw exception

  sigbuf = (unsigned char *)OPENSSL_malloc( sizeof *sigbuf * sigbuf_length );
  if ( !sigbuf )
    // throw exception

  if ( EVP_DigestSignFinal( ctx, sigbuf, &sigbuf_length ) != 1 )
    // throw exception

  std::copy( sigbuf, sigbuf + sigbbuf_length, std::back_inserter( signature ) );

  EVP_MD_CTX_destroy( ctx );
  OPENSSL_free( sigbuf ); // yes, there's potential for a memory leak, but I'm just trying to get this bastard to work.
}

繰り返しますが、このコードから生成された署名は、次の結果と一致しません。

openssl rsautl -sign -inkey keyfile.pem -keyform PEM -in msg.txt -out signature

問題は秘密鍵のロード方法にあると確信していますが、これまでに見たすべての例は、これが機能することを示しています。

私はこれを見つめて、2日間髪を引っ張っています. 提案、ヒント、ガイダンス、失礼な発言などは大歓迎です。

ありがとう。

編集

いくつかの例は、私が反対していることを示しているはずです。

以下SignedInfoは、特定のメッセージに対して生成されたものです。

<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-exc-c14n#">
    <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="alws soapenv"/>
  </ds:CanonicalizationMethod>
  <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
  <ds:Reference URI="#TS-5b171864-232b-11e9-846f-00505695541c">
    <ds:Transforms>
      <ds:Transform Algorithm="http://www.w3.org/2006/12/xml-exc-c14n#">
        <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="wsse alws soapenv"/>
      </ds:Transform>
    </ds:Transforms>
    <ds:DigestValue>eeLn6ak1glbbbWE48q7olsxO0CO/fL85bZ+8hzcjrvE=
</ds:DigestValue>
    <ds:DigestMethod Algorithm="https//www.w3.org/2001/04/xmlenc#sha256"/>
  </ds:Reference>
</ds:SignedInfo>

タイムスタンプからダイジェスト値が計算されます。

<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="TS-5b171864-232b-11e9-846f-00505695541c">
  <wsu:Created>2019-01-28T18:34:33Z</wsu:Created>
  <wsu:Expires>2019-01-28T18:34:38Z</wsu:Expires>
</wsu:Timestamp>

コマンドラインからそのタイムスタンプのダイジェストを計算すると、次のようになります。

$ openssl dgst -sha256 -binary timestamp > timestamp.dgst

同じダイジェスト値を取得します。

$ openssl base64 -in timestamp.dgst
eeLn6ak1glbbbWE48q7olsxO0CO/fL85bZ+8hzcjrvE=

ここまでは順調ですね。そのハッシュが に追加されSignedInfo、次のハッシュが取得されSignedInfoます。

cQaWLGHi8D/c1kXPG9i49xzAupeBuypvMvuMQlzA/wo=

そして、それを使用して署名を生成します。さて、ここで事態は完全に常軌を逸しています。上記のコードを使用して署名を生成すると、次のようになります。

HtQ4LkYq4Eao4bMOpV4SBpMxHi2a+0ilxDXS9jIQZWdCC8HCNlpvVU4rWMZG2Zd/
LplCWmUHIaB35FKv6uKjCjJPVDAJT2agyp7FnSKxaBI44Y/YsdvKyxJTAMiAlF8i
dd1MB8ljYsfayrzq5e76kt2cbHlYkT/RM3SvwJtjZiYsNpfcXD0Bi6JhRshHxQ8s
6/errruOe7jUqbKh7UOPJokadCX0OTSSwRgcs+sm7VjnS9MYILaGzFFT3Js9xI6d
TL4B6A/JGIkEqLO+GA1lrokAeIBr9OVUu7OEzaBb7DaiP9Gv1diu0j1sbZ4uT5Cf
CjYJPYU72Xx8F+MKdSJteg==

コマンドライン ツールを使用すると、次のようになります。

PvfCDqPl86/8USbFU0XR5r1Dhl5JbWd2va3L4W1IW1zw6xdes04F4lYjol6gMKio
jyr8DdmWBquroVlo4vW8kmhr6760qMcpK6mfsZ26ftu7XRC+Z4b9ge6ICOemsGlE
04Yoh9EpECP+ei5yS4E1sbntteiSoQcjotmVcIbPaEG5DIDcd4JKfoCWmsnuZESs
qctIJAQy4YY9HJsVGJ2JG7QashFcEQJabtInFgYeKuxla0ZSXBfOBkwHZT/cSv+k
n/NqPMCyEl4B2LiPBVa36GaTUd6fx0SXnIh0Fm+jw6b6j3EjU0QfMJ/JBAlL+oWZ
fXO/pS5L7W+OWk8Fh//iKA==

コマンド ラインで生成された署名を検証すると、元のハッシュが返されます。

 $ openssl base64 -d -in signature.b64 > signature.reversed

 $ openssl rsautl -verify -inkey cert.pem -certin -in signature.reversed > signature.reversed.dgst

$ openssl base64 -in signature.reversed.dgst
cQaWLGHi8D/c1kXPG9i49xzAupeBuypvMvuMQlzA/wo=

コードによって生成された署名を検証しようとすると、元のハッシュが返されません。

$ openssl base64 -d -in badsig.b64 > badsig

$ openssl rsautl -verify -inkey cert.pem -certin -in badsig > badsig.dgst

$ openssl base64 -in badsig.dgst
MDEwDQYJYIZIAWUDBAIBBQAEIHEGlixh4vA/3NZFzxvYuPccwLqXgbsqbzL7jEJc
wP8K

特にイライラするのは、署名を作成した後に署名を検証するためのコードを追加したことです。そのコードはパスします。しかし、明らかに間違っています。ハッシュが一致せず、openssl コマンド ライン ツールによって生成されたものと一致しないため、リモート サービスはリクエストを拒否します。使用しているコマンド ライン ツールとライブラリの両方が同じバージョン (1.0.1) であることを確認しました。

キーファイルの内容と比較するために秘密キーをダンプするコードを追加しましたが、一致するため、キーを正しく読み取っています。

libcrypto ルーチンを使用してメッセージに署名するには、EVP_Sign()、EVP_DigestSign()、EVP_PKEY_sign() の 3 つ以上の方法があるようですが、私の場合はどれを使用するのが正しいかわかりません。3 つすべてが悪い署名を与えます (つまり、公開鍵に対して復号化すると、元のハッシュ値にはなりません)。

繰り返しになりますが、誰かが私がしていることは明らかに間違っていると指摘できれば、私はそれを感謝します.

もっと編集

また、上記のブロックdgstを使用して、次のように検証しようとしています。SignedInfo

$ openssl dgst -sha256 -binary -sign fx-realtime.fundsxpress.com.pem -out signature signedinfo

$ openssl dgst -sha256 -binary -verify publickey.pem -signature signature signedinfo
Verified OK

私のコードが生成する署名を逆にする:

$ echo -n 'XfgP1A08UTwz3sUHIVvvV+fq1n3act6+lVBZ8ieDtgh28k1r1/M0tm9MntvK+Hm4
> Be+LjguX2gxhZ4PvVcoCBCugDIsrhxplDeB4bYeY2PEedQL6+IZFX+kFrz6o3RQa
> W7sXK7czogxWpdLAmKnhDJOk2BmKFihkRMTjo9D4z/qylZI9nnX29HNdg3uV2BYw
> zHh8GvYO8fy1ugqfFW80na+hLBAtBP6fwTTv10DS2L8n+ixQcnxlKW5pyBOXlR/r
> mZEqwU+A996G0573HkGFeFvXzArlRFg/7mkKoyUHyqyDzkf5eC+vTnpEy1CP75Yc
> lvd7ldSrwREisPnyxu47sg=='> computed_signature.b64

$ openssl base64 -e -in computed_signature.b64 > computed_signature

$ openssl dgst -sha256 -binary -verify publickey.pem -signature computed_signature signedinfo
Verification Failure
4

2 に答える 2

0

コードは問題なく、生成された署名も問題ありません。あなたが見逃しているのは、署名を生成するたびに毎回異なるということです。検証を通じて署名を実行すると、それらはすべて機能します。理由はわかりませんが、このようにするのにはセキュリティ上の理由があると思います。

于 2019-01-27T17:11:30.003 に答える