无法解密签名的S / Mime消息

I'm at the moment realizing an S/Mime decryption using PHP. What i got so far:

    $keys = array("public"=>$atm."/public-keys/".$usr.".smime",
        "private"=>$atm."/private-keys/".$usr.".smime");
    if(!file_exists($keys["public"])) die("Public Key not found");
    if(!file_exists($keys["private"])) die("Private Key not found");
    $public = file_get_contents($keys["public"]);
    $private = file_get_contents($keys["private"]);

    switch($_GET["debug"])
    {
        case "encrypt":
        {
            $outfile = realpath("demo-msg/out.txt");
            $outfile_signed = realpath("demo-msg/out.signed.txt");
            $infile = realpath("demo-msg/in.txt");

            file_put_contents($infile,$msg);
            $adddata = array("To" => "XXX", "From: Demo Name <XXX>", "Subject" => "Demo Subject");
            if (openssl_pkcs7_encrypt($infile, $outfile, $public, $adddata))
            {
                //$info = file_get_contents($outfile);
                echo "winenc & transfer<br>
";
                file_put_contents($infile, file_get_contents($outfile));
                //if(openssl_pkcs7_sign($outfile,$outfile_signed,$public,$private,$adddata, PKCS7_BINARY)) echo "winsign";
                //else echo "failsign";
            } 
            else echo "Failed Encryption";
            exit;
        }
        default:
        {
            $outfile2 = realpath("demo-msg/out2.txt");
            $outfile = realpath("demo-msg/out.txt");
            $infile = realpath("demo-msg/smime.p7m");
            //$infile = realpath("demo-msg/in.txt");

            if(openssl_pkcs7_verify($infile)) echo "verified<br>
"; //tried: openssl_pkcs7_verify($infile,$PKCS7_DETACHED, tmpfile(), array(), array(), $outfile)
            else die("invalid sig");

            if(openssl_pkcs7_decrypt($infile, $outfile2, $public, $private)) //tried: openssl_pkcs7_decrypt($outfile, $outfile2, $public, $private)
            {
                echo "dec win:".file_get_contents($outfile2);
            }
            else echo "Oh oh! Decryption failed!";
            exit;
        }
    }

What this snippet already can do:

  • Encrypt a Message
  • Decrypt an encrypted message (created by itself)
  • Decrypt an encrypted message (Office 2010) as long as it's not signed

Now, i want to decrypt messages that are signed too (as it's usually one step). The Problem:

  • If i first try a decrypt, it'll return the encrypted message with different headers. Multiple decryptions lead to the same result.
  • My thought was using the $content - parameter of the verification - command (openssl_pkcs7_verify). You can see my attempt in the code-comments.

Nevertheless, i don't have any clues what can be wrong with the second attempt. ANy help would be appreciated!

Speaking to myself.

Errors i made in the script:

  • Verification returns -1 (error), but i process it as true (success). The verification never worked.
  • The Verification is plain wrong. The DETACHED is a constant, not a variable. The "extracert" parameter expects a valid file as string containing a valid signature. Though, the idea i had was right (de-signing using the "content"-parameter).
  • Order of signing and decryption

What i misunderstood was the way, signatures are processed (and verifications are made). I assumed the message gets encrypted, then signed. It can be that way, but a lot of tools, including Office2010 first sign the message, then encrypt it. That way you can't check the signature before decrypting and have to de-sign after the decryption.

You can see my debugging-code that works down below. This will help you with your decryption problems when stumbling upon this thread.

            $test = openssl_pkcs7_verify($infile, PKCS7_DETACHED ); //just to see that it doesn't work
            echo "signature is ".$test."
<br>".openssl_error_string(); 

            $dec = openssl_pkcs7_decrypt($infile, $outfile, $public, $private);
            echo "<br><br>

dec is ".$dec."
<br>".openssl_error_string()."
<br>".file_get_contents($outfile); 

            $test = openssl_pkcs7_verify($outfile, PKCS7_DETACHED, $tmp, array(), $tmp, $outfile2 );
            echo "<br><br>

signature2 is ".$test."
<br>".openssl_error_string()."
<br>".file_get_contents($outfile2);