5

有効な PKCS7 ファイルを CMSSignedData オブジェクトにロードしました。この PKCS7 ファイルには、プレーン テキスト メッセージと有効な添付デジタル署名が含まれています (すべて同じファイルに含まれています)。

今、このファイルにタイムスタンプを付けたいと思います。これは私が使用しているコードです(source):

 private static CMSSignedData addTimestamp(CMSSignedData signedData)
throws Exception {
        Collection ss = signedData.getSignerInfos().getSigners();
        SignerInformation si = (SignerInformation) ss.iterator().next();

        TimeStampToken tok = getTimeStampToken();

        ASN1InputStream asn1InputStream = new ASN1InputStream
(tok.getEncoded());
        DERObject tstDER = asn1InputStream.readObject();
        DERSet ds = new DERSet(tstDER);

        Attribute a = new Attribute(new
DERObjectIdentifier("1.2.840.113549.1.9.16.2.14"), ds);
        DEREncodableVector dv = new DEREncodableVector();
        dv.add(a);
        AttributeTable at = new AttributeTable(dv);
        si = SignerInformation.replaceUnsignedAttributes(si, at);
        ss.clear();
        ss.add(si);
        SignerInformationStore sis = new SignerInformationStore(ss);

        signedData = CMSSignedData.replaceSigners(signedData, sis);
        return signedData;
    }


 private static TimeStampToken getTimeStampToken() throws
Exception {
        Security.addProvider (new
org.bouncycastle.jce.provider.BouncyCastleProvider());

        PostMethod post = new PostMethod("http://My-TrustedTimeStampProvier.com");

// I'm omitting the part where I pass the user and password

        TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
        //request TSA to return certificate
        reqGen.setCertReq (true); // In my case this works

        //make a TSP request this is a dummy sha1 hash (20 zero bytes)
        TimeStampRequest request =
            reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));

        byte[] enc_req = request.getEncoded();
        ByteArrayInputStream bais = new ByteArrayInputStream(enc_req);

        post.setRequestBody(bais);
        post.setRequestContentLength (enc_req.length);
        post.setRequestHeader("Content-type","application/timestamp-query");

        HttpClient http_client = new HttpClient();
        http_client.executeMethod(post);
        InputStream in = post.getResponseBodyAsStream();

        //read TSP response
        TimeStampResponse resp = new TimeStampResponse (in);

        resp.validate(request);

        TimeStampToken  tsToken = resp.getTimeStampToken();       
        return tsToken;
    }  

有効な TimeStamp を取得でき、それを CMSSignedData オブジェクトに入れて、signedData.getEncoded() からのバイトをハードディスクに書き込むファイルに保存できます。しかし、サードパーティのソフトウェアを使用して新しいタイムスタンプ付きファイルを検証すると、このソフトウェアは元の署名は問題ないことを通知しますが、タイムスタンプは署名と一致しません。このソフトウェアは、元のプレーン テキスト メッセージを表示することもできます。

問題は次の行にあると思います。

TimeStampRequest request =
    reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));

ダミーのバイト配列の代わりにダイジェストを渡す必要があると思いますが、どのダイジェストか、タイムスタンプに必要な正しいバイトがわかりません。SignerInformationからオブジェクトを正常に取得して検証できましたsignedDatareqGen.generate()次に、からのバイトを関数に渡そうとしましたmySignerInformation.getSignature()。タイムスタンプの検証に失敗しました。その後、 の Sha1 ダイジェストに合格しましたmySignerInformation.getSignature()が、タイムスタンプの検証に再び失敗しました。

RFC3161 仕様には次のように記載されています。

2.4.1. リクエスト形式

タイムスタンプ要求は次のとおりです。

TimeStampReq ::= SEQUENCE { version INTEGER { v1(1) }, messageImprint MessageImprint, -- ハッシュ アルゴリズム OID とデータのハッシュ値

(...)

messageImprint フィールドには、タイムスタンプを付けるデータのハッシュを含める必要があります。ハッシュは OCTET STRING として表されます。その
長さは、そのアルゴリズムのハッシュ値の長さと一致する必要があります
(たとえば、SHA-1 の場合は 20 バイト、MD5 の場合は 16 バイト)。

MessageImprint ::= SEQUENCE { hashAlgorithm AlgorithmIdentifier, hashedMessage OCTET STRING }

しかし、CMSSignedData オブジェクト内のバイトをタイムスタンプしたい場合、MessageImprint データをどこでどのように取得するかはわかりません。

私はこのデジタル署名の初心者です。

4

1 に答える 1