> -----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

Reply via email to