Closed
Bug 1340103
Opened 7 years ago
Closed 7 years ago
Introduction of SECKEYECPublicKey.encoding in NSS 3.28 broke ABI.
Categories
(NSS :: Libraries, defect)
Tracking
(Not tracked)
RESOLVED
FIXED
3.30
People
(Reporter: KaiE, Assigned: KaiE)
References
Details
Attachments
(1 file, 8 obsolete files)
12.25 KB,
patch
|
KaiE
:
review+
|
Details | Diff | Splinter Review |
Another ABI compatibility issue might have been introduced in NSS 3.28. SECKEYECPublicKey was extended, and attribute ECPointEncoding encoding was added at the end of the structure. SECKEYECPublicKey is embedded as part of a union in SECKEYPublicKey. According to Bob, some applications create SECKEYPublicKey objects, and pass it to NSS. When NSS processes SECKEYPublicKey, how does it know if the SECKEYECPublicKey.encoding attribute has been set, or contains garbage (because an old application uses it, that didn't know about that new attribute) ? The risk is that NSS might behave incorrectly, when it consumes externally produced public key data. Bob suggested that NSS must check, whether or not its safe to access SECKEYECPublicKey.encoding, prior to using it. How can NSS find out, if that's safe or not? The new attribute "encoding" is an enum, with two values, ECPoint_Uncompressed and ECPoint_XOnly. I've looked at all the places where NSS uses these values. Both seckey_SetPointEncoding and ssl_ImportECDHKeyShare set the encoding based on other information, which seems safe. The only remaining place is pk11_ECPubKeySize, which reads the encoding attribute to draw conclusions. That function is used from one context, only, by pk11_PubDeriveECKeyWithKDF. Is it possible that pk11_PubDeriveECKeyWithKDF may operate on externally imported public key data? If yes, how do we ensure that accessing the encoding attribute is safe? Bob made the general suggestion (prior to knowing about this place of use), that before looking at this attribute, we should look at the first attribute of SECKEYECPublicKey, which is SECKEYECParams DEREncodedParams. IIUC, Bob said, SECKEYECParams DEREncodedParams contains the OID of the curve, is this correct? He suggested, only if that parameter shows it's curve 25519 or newer, only then look at the new "encoding" attribute. Does everyone agree? How can we do that? What strategy can we use, to decide that the given curve OID points to one, that is either curve 25519, or was added to NSS afterwards? Once we know how to do that, all places that access SECKEYECPublicKey.encoding, must go through that decision, and only if the curve is "25519 or added later", only then it's safe to access the "encoding" attribute, and if it's not, then the code must assume that encoding is the classic value ECPoint_Uncompressed. Is this summary correct?
Assignee | ||
Comment 1•7 years ago
|
||
It seems that attribute ECPointEncoding encoding is redundanct, because the information can be derived from the initial member of SECKEYECPublicKey. This patch removes all mention of the new attribute, and changes the only place where that attribute was ever read.
Assignee | ||
Updated•7 years ago
|
Attachment #8838026 -
Flags: review?(franziskuskiefer)
Assignee | ||
Updated•7 years ago
|
Attachment #8838026 -
Attachment is obsolete: true
Attachment #8838026 -
Attachment is patch: false
Attachment #8838026 -
Flags: review?(franziskuskiefer)
Assignee | ||
Comment 2•7 years ago
|
||
My earlier patch had a small cleanup glitch. In addition, with trunk, the following test failed. Thank you for having created that test. // Importing a public key in SPKI format must fail when id-ecPublicKey is // given (so we know it's an EC key) but the namedCurve parameter is missing. TEST_F(Pkcs11EcdsaSha256Test, ImportSpkiNoAlgorithmParams) { EXPECT_FALSE(ImportPublicKey(kP256SpkiNoAlgorithmParams, sizeof(kP256SpkiNoAlgorithmParams))); }
Assignee | ||
Comment 3•7 years ago
|
||
Assignee | ||
Comment 4•7 years ago
|
||
Comment on attachment 8838093 [details] [diff] [review] 1340103-v3-trunk.patch Franziskus, what do you think? The patch passes tests: https://treeherder.mozilla.org/#/jobs?repo=nss-try&revision=33a8e9d74674f54ec97446e56fb82e65b6f1d847 If Bob's statement is correct, that applications could try to pass SECKEYECPublicKey* into NSS, then it would be tricky to ensure, that it has been set, prior to reading it. Because the information stored in the "encoding" attribute seems redundant, I'm trying to remove it, and whenever we read it, derive it from the curve OID. I don't know if any application is already reading the "encoding" attribute. Do we think it's necessary to set it anyway, even if NSS itself never reads it? (For applications based on NSS 3.28 or later, that already read the attribute.) Maybe it would be safer, but a hassle to maintain the attribute going forward (if we never read it, and only write it). If any application already attempts to set the attribute, we can simply ignore that, since we can derive it from the curve OID. I've replaced the attribute with an anonymous enum, to ensure we at least reserve the space for that attribute, to ensure that space never gets reused for something else.
Attachment #8838093 -
Flags: review?(franziskuskiefer)
Assignee | ||
Comment 5•7 years ago
|
||
(In reply to Kai Engert (:kaie) from comment #4) > > I don't know if any application is already reading the "encoding" attribute. > Do we think it's necessary to set it anyway, even if NSS itself never reads > it? (For applications based on NSS 3.28 or later, that already read the > attribute.) Alternatively, we could keep the old enum values, but never use them. We could add a third enum value, ECPoint_undefined, and always set the encoding attribute to undefined. That way, applications that already attempt to read it, can notice that they aren't getting the expected values any more.
Assignee | ||
Comment 6•7 years ago
|
||
Attachment #8838093 -
Attachment is obsolete: true
Attachment #8838093 -
Flags: review?(franziskuskiefer)
Attachment #8838122 -
Flags: review?(franziskuskiefer)
Assignee | ||
Updated•7 years ago
|
Attachment #8838122 -
Flags: review?(rrelyea)
Assignee | ||
Updated•7 years ago
|
See Also: → curve25519
Comment 7•7 years ago
|
||
Comment on attachment 8838122 [details] [diff] [review] 1340103-v4-trunk.patch Review of attachment 8838122 [details] [diff] [review]: ----------------------------------------------------------------- ::: lib/pk11wrap/pk11skey.c @@ +2048,2 @@ > > + /* Is it a curve that is known to use a special encoding? */ This test should be in it's own function. The issue is there will be more curves with this encoding. The function should return the encoding based on the curve type. The function wout look like the old seckey_SetPointEncoding function you removed in this patch, but instead return the encoding type.
Comment 8•7 years ago
|
||
The rest looks fine. I think this change was made in response to a review I did on franziskus's code where I wanted to isolate the number of places that new about curve 25519 explicitly, knowing we may be adding other berstein curves in the future. bob
Assignee | ||
Comment 9•7 years ago
|
||
just FYI, this is the delta change that should implement Bob's request. I'll attach the new full patch next.
Assignee | ||
Comment 10•7 years ago
|
||
Assignee: nobody → kaie
Attachment #8838122 -
Attachment is obsolete: true
Attachment #8838122 -
Flags: review?(rrelyea)
Attachment #8838122 -
Flags: review?(franziskuskiefer)
Attachment #8838197 -
Flags: review?(rrelyea)
Assignee | ||
Comment 11•7 years ago
|
||
I realize, in addition to splitting, you've also asked me to reuse the old implementation strategy for the split function. I'll have that in a few minutes.
Assignee | ||
Comment 12•7 years ago
|
||
Attachment #8838196 -
Attachment is obsolete: true
Attachment #8838197 -
Attachment is obsolete: true
Attachment #8838197 -
Flags: review?(rrelyea)
Assignee | ||
Comment 13•7 years ago
|
||
try run with patch v6: https://treeherder.mozilla.org/#/jobs?repo=nss-try&revision=673256e13f770fd42d65979c333a5f8656d8778b
Assignee | ||
Updated•7 years ago
|
Attachment #8838204 -
Flags: review?(rrelyea)
Comment 14•7 years ago
|
||
Comment on attachment 8838204 [details] [diff] [review] 1340103-v6-trunk.patch Review of attachment 8838204 [details] [diff] [review]: ----------------------------------------------------------------- ::: lib/cryptohi/seckey.c @@ +1180,5 @@ > &pubk->u.ec.DEREncodedParams); > if (rv != SECSuccess) { > break; > } > + copyk->u.ec.encoding = ECPoint_Undefined; You should probably call seckey_HasCurveOID() here as well. It will at least ensure that copied public keys are correct. @@ +1262,5 @@ > CKA_EC_POINT, arena, &pubk->u.ec.publicValue); > if (rv != SECSuccess || pubk->u.ec.publicValue.len == 0) { > break; > } > + pubk->u.ec.encoding = ECPoint_Undefined; This one is safe, on the assumption that the OID is correctly set on the private key. ::: lib/pk11wrap/pk11skey.c @@ +2045,5 @@ > + SECItem oid; > + SECStatus rv; > + ECPointEncoding encoding = ECPoint_Undefined; > + > + PLArenaPool *arena = PORT_NewArena(2048); You can use a cheap arena here and save a heap allocation: https://searchfox.org/nss/rev/ffa508ee08f7b04bdfb9e73408fe5d5902198c11/lib/util/secport.h#102-104 @@ +2060,5 @@ > + case SEC_OID_CURVE25519: > + encoding = ECPoint_XOnly; > + break; > + case SEC_OID_SECG_EC_SECP256R1: > + /* fall through */ The fall through comments aren't necessary if you don't have any statements after the label. ::: lib/util/eccutil.h @@ +4,5 @@ > > #ifndef _FREEBL_H_ > #define _FREEBL_H_ > > /* point encoding type */ Did you want to mark this as deprecated here too?
Comment 15•7 years ago
|
||
Comment on attachment 8838204 [details] [diff] [review] 1340103-v6-trunk.patch Review of attachment 8838204 [details] [diff] [review]: ----------------------------------------------------------------- I'm also ok with you incorporating any of martin's suggested fixes, including the one I commented on. ::: lib/cryptohi/seckey.c @@ +1180,5 @@ > &pubk->u.ec.DEREncodedParams); > if (rv != SECSuccess) { > break; > } > + copyk->u.ec.encoding = ECPoint_Undefined; Martin's suggestion is good sanity, though it's hard to see how copy could fail without an error code. It would prevent copying a deficient key (one in which the params were not encoded correctly. One thing about using the HasCurveOID is it allocates extra memory in the arena that we never use, so it's probably a good idea not to overuse it. It's not a leak since it only happens once per key and it's tied to the key's arena. Probably best to keep it as is.
Attachment #8838204 -
Flags: review?(rrelyea) → review+
Assignee | ||
Comment 16•7 years ago
|
||
Bob, Martin, very helpful feedback, thanks a lot. I think we can address Bob's worry about allocation overhead by using a local PORTCheapArenaPool inside seckey_HasCurveOID.
Assignee | ||
Comment 17•7 years ago
|
||
Delta patch that addresses the change requests.
Assignee | ||
Comment 18•7 years ago
|
||
Updated patch v7, carrying forward r=rrelyea
Attachment #8838204 -
Attachment is obsolete: true
Attachment #8838466 -
Flags: review+
Assignee | ||
Comment 19•7 years ago
|
||
minor adjustment after self review, in SECKEY_CopyPublicKey, I've moved seckey_HasCurveOID to happen earlier. If the source is broken, we avoid copying.
Attachment #8838465 -
Attachment is obsolete: true
Attachment #8838466 -
Attachment is obsolete: true
Attachment #8838469 -
Flags: review+
Assignee | ||
Comment 20•7 years ago
|
||
fixed for 3.30 https://hg.mozilla.org/projects/nss/rev/608b71f014fa
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → 3.30
Assignee | ||
Comment 21•7 years ago
|
||
Backported to 3.29 branch for 3.29.1: https://hg.mozilla.org/projects/nss/rev/98031786f9cc Backported to 3.28 branch for 3.28.3: https://hg.mozilla.org/projects/nss/rev/0050234a859c Only difference was the change to SECKEY_ConvertToPublicKey, which was omitted, because that function doesn't handle EC keys on the older branches.
You need to log in
before you can comment on or make changes to this bug.
Description
•