> -----Original Message----- > From: dev-tech-crypto-bounces+ryan- > [email protected] [mailto:dev-tech-crypto- > [email protected]] On Behalf > Of Matej Kurpel > Sent: Sunday, November 28, 2010 11:24 AM > To: mozilla's crypto code discussion list > Subject: Re: Certificate login in Firefox - how does it work? >
[snip] > On 26. 11. 2010 22:20, [email protected] wrote: > > While I've not spent time hacking with PCKS#11, my understanding is > > that the C_Sign function should be treating the input as raw/opaque, > > dictated by the mechanism that was used to initialize. If you're > > relying on the input being in a particular format, you need to ensure > > that format is specified in the underlying PKCS#11 specification for > > that mechanism, otherwise it sounds like you're making assumptions that > > shouldn't be made. > This assumption is made by NSS and not by me. When signing e-mail in > Thunderbird, it sends DigestInfo (with DER-encoded OID and Hash value), > and when performing a SSL login, it sends raw data. The mechanism used > is always CKM_RSA_PKCS. I don't have a bulletproof way to determine > which of these two cases it is. What I meant to say is that your attempt to interpret the data being sent in is an assumption: that the data is meaningful. According to the PKCS#11 specification, you are just supposed to sign the data as provided, provided it meets the constraints inposed (l <= k-11). You're correct that, in the case of Thunderbird, it will send a full DigestInfo structure to be signed [1], while in the case of TLS client auth, it only sends the hashes [2]. In an "ideal world", your PKCS#11 module should not ascribe any meaning to that data. Please consider reviewing the PKCS#11 specification again [3]. For CKM_RSA_PKCS, it reads "This mechanism corresponds only to the part of PKCS #1 v1.5 that involves RSA; it does not compute a message digest or a DigestInfo encoding as specified for the md2withRSAEncryption and md5withRSAEncryption algorithms in PKCS #1 v1.5 ." The actual specification for PKCS #1 v1.5 is at [4]. Section 10.1 details how signatures are computed, and includes this: "The signature process consists of four steps: message digesting, data encoding, RSA encryption, and octet-string-to-bit-string conversion." When combined with what the PKCS#11 specification says for how the CKM_RSA_PKCS method behaves, it becomes clear that the mechanism should only apply the last two steps: "RSA encryption, and octet-string-to-bit-string conversion." The PKCS #1 v1.5 specification details the RSA encryption portion of signatures in section 10.1.3, which states that it should be computed using the behaviour described in Section 8.1 with a block type of 01 and a private key as described in Section 7. Ignoring the private key format as unrelated to this discussion, Section 8.1 describes the Encryption behaviour. While not intending to quote the whole thing, the format is described as: A block type BT, a padding string PS, and the data D shall be formatted into an octet string EB, the encryption block. EB = 00 || BT || PS || 00 || D . (1) Putting it all together, when PK11_Sign/C_Sign is called with CKM_RSA_PKCS, what you are provided as input is D. It may be a DigestInfo, where the caller has computed the hash of the original message M, and then encoded both it and the hash mechanism OID into the structure, as Thunderbird does and as specified by PKCS #7. But it may also be a "bare" hash, as described in TLS v1.0, where the DigestInfo is omitted and D is the concatenation of both the MD5 and SHA-1 hashes. Or it may be neither - simply raw data that should be encrypted, perhaps by using some new method that accommodates some weakness in the PKCS #1 v1.5 encryption/signature method. [5] In terms of conceptualizing the relationship between PKCS#11's CKM_RSA_PKCS and the PKCS #1 v1.5 specification, "PK11_Sign" is better thought of as "PK11_Encrypt" - the behaviour of the mechanism is specified by Section 8.1, Encryption, rather than Section 10.1, Signatures. As I mentioned, CryptoAPI does not expose this raw functionality - it only allows "encryption" of previously computed hashes, and it will compute the DigestInfo for you before encrypting. However, as I mentioned, you can suppress the computing the DigestInfo by passing CRYPT_NOHASHOID. Further, you can import the hash, generated via NSS, into CryptoAPI, by using CALG_SSL3_SHAMD5 and using CryptSetHashParam(HP_HASHVAL). This works because your input data, D, is 36 bytes, the same length as CALG_SSL3_SHAMD5, and presumably the CSP allows you to set HP_HASHVAL. The net result of this is the behaviour you desire. The reason why this is important is that lets say another application wishes to use your PKCS #11 module. Rather than implementing PKCS #7 or TLS 1.0, it implements the vendor-specific Sleevinet protocol ("The future of the Intertubes"). The Frooble message of the Sleevinet protocol is described as the RSA encrypted string "HACK ME" (48 41 43 4B 4D 45), encrypted according to PKCS #1 v1.5 using block type 01. Such an application would call PK11_Sign (in NSS) with CKM_RSA_PKCS, which would (eventually) call C_Sign in your module. The ulDataLen pased to C_Sign will be 7, and the pData will point to the sequence of bytes above. Your PKCS#11 module would be expected to output the encrypted result of the sequence 00 || 01 || PS || 00 || 48 || 41 || 43 || 4B || 4D || 45, where PS is the padding string. With CryptoAPI, you can't pass those arbitrary 7 bytes in to be encrypted, so your module would fail to work for the Sleevinet protocol. This is, quite probably, an academic point. In all of NSS, today, there are only three calls to PK11_Sign: ssl3_SignHashes, SGN_End, and SGN_Digest. For RSA (and RSA alone), In ssl3_SignHashes, your input is always 36 bytes, and in SGN_End/SGN_Digest, the input is always the DER-encoded DigestInfo. It's probably sufficient to do what you're doing. However, from a PKCS #11 standpoint, the module isn't really compatible. It's probably fine, but I just wanted to clarify to make sure it was understood why/how it works :-) I hope this has been helpful, and I'm glad to hear you were able to get the rest of your tests working using P/Invoke. [1] http://mxr.mozilla.org/comm-central/source/mozilla/security/nss/lib/cryptohi /secsign.c?mark=424,452#396 [2] http://mxr.mozilla.org/security/source/security/nss/lib/ssl/ssl3con.c#845 [3] ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/v2-20/pkcs-11v2-20.pdf [4] ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1.asc [5] Yes, I'm ignoring RSA-OAEP/PSS intentionally. -- dev-tech-crypto mailing list [email protected] https://lists.mozilla.org/listinfo/dev-tech-crypto

