Merge ~athos-ribeiro/ubuntu/+source/nss:lp1959126-upstream-3.68.2 into ubuntu/+source/nss:ubuntu/devel
- Git
- lp:~athos-ribeiro/ubuntu/+source/nss
- lp1959126-upstream-3.68.2
- Merge into ubuntu/devel
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | e7ce70b8a296c4b8875570711405bbee45fe3468 | ||||
Proposed branch: | ~athos-ribeiro/ubuntu/+source/nss:lp1959126-upstream-3.68.2 | ||||
Merge into: | ubuntu/+source/nss:ubuntu/devel | ||||
Diff against target: |
1147 lines (+350/-421) 16 files modified
debian/changelog (+8/-0) debian/patches/series (+0/-1) dev/null (+0/-282) nss/.hg_archival.txt (+3/-3) nss/gtests/certdb_gtest/decode_certs_unittest.cc (+13/-0) nss/gtests/mozpkix_gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp (+71/-1) nss/lib/cryptohi/secvfy.c (+121/-71) nss/lib/mozpkix/include/pkix-test/pkixtestutil.h (+8/-0) nss/lib/mozpkix/include/pkix/pkixutil.h (+14/-0) nss/lib/mozpkix/lib/pkixocsp.cpp (+55/-37) nss/lib/mozpkix/lib/pkixverify.cpp (+1/-8) nss/lib/mozpkix/test-lib/pkixtestutil.cpp (+45/-12) nss/lib/nss/nss.h (+2/-2) nss/lib/pkcs7/certread.c (+5/-0) nss/lib/softoken/softkver.h (+2/-2) nss/lib/util/nssutil.h (+2/-2) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Lucas Kanashiro (community) | Approve | ||
Canonical Server | Pending | ||
Review via email: mp+415883@code.launchpad.net |
Commit message
Description of the change
This MP updates nss from 3.68 to 3.68.2. Note that this new version is not available in Debian, which is already in 3.7x. We decided to remain in 3.68.2 due to the fact that it is an LTS release and is more suitable for jammy.
This new version includes two bug fixes. One of them was already applied in our delta (hence the dropped patch). It also adds support to SHA-2 hashes in CertIDs in OCSP responses.
There are no symbol changes for this new version and no transition should be required.
a PPA with the proposed changes is available at:
https:/
This package has no dep8 tests.
Lucas Kanashiro (lucaskanashiro) wrote : | # |
I overlooked the CVE number, it was already fixed in the previous release :) no need to mention it again, sorry for the noise.
Lucas Kanashiro (lucaskanashiro) wrote : | # |
Package uploaded as requested by Athos:
$ dput ubuntu ../nss_
Checking signature on .changes
gpg: ../nss_
Checking signature on .dsc
gpg: ../nss_
Uploading to ubuntu (via ftp to upload.ubuntu.com):
Uploading nss_3.68.
Uploading nss_3.68.
Uploading nss_3.68.
Uploading nss_3.68.
Uploading nss_3.68.
Successfully uploaded packages.
Preview Diff
1 | diff --git a/debian/changelog b/debian/changelog |
2 | index dcda4b0..2bfdd70 100644 |
3 | --- a/debian/changelog |
4 | +++ b/debian/changelog |
5 | @@ -1,3 +1,11 @@ |
6 | +nss (2:3.68.2-0ubuntu1) jammy; urgency=medium |
7 | + |
8 | + * New upstream release. (LP: #1959126) |
9 | + * d/p/CVE-2021-43527.patch: drop patch applied upstream. |
10 | + [ Fixed in 3.68.1 ] |
11 | + |
12 | + -- Athos Ribeiro <athos.ribeiro@canonical.com> Mon, 21 Feb 2022 14:55:42 -0300 |
13 | + |
14 | nss (2:3.68-1ubuntu2) jammy; urgency=medium |
15 | |
16 | * SECURITY UPDATE: heap overflow when verifying DSA/RSA-PSS DER-encoded |
17 | diff --git a/debian/patches/CVE-2021-43527.patch b/debian/patches/CVE-2021-43527.patch |
18 | deleted file mode 100644 |
19 | index a663236..0000000 |
20 | --- a/debian/patches/CVE-2021-43527.patch |
21 | +++ /dev/null |
22 | @@ -1,282 +0,0 @@ |
23 | -Description: fix heap overflow when verifying DSA/RSA-PSS DER-encoded signatures |
24 | -Origin: Provided by Mozilla |
25 | - |
26 | -diff --git a/nss/lib/cryptohi/secvfy.c b/nss/lib/cryptohi/secvfy.c |
27 | ---- a/nss/lib/cryptohi/secvfy.c |
28 | -+++ b/nss/lib/cryptohi/secvfy.c |
29 | -@@ -164,6 +164,37 @@ |
30 | - PR_FALSE /*XXX: unsafeAllowMissingParameters*/); |
31 | - } |
32 | - |
33 | -+static unsigned int |
34 | -+checkedSignatureLen(const SECKEYPublicKey *pubk) |
35 | -+{ |
36 | -+ unsigned int sigLen = SECKEY_SignatureLen(pubk); |
37 | -+ if (sigLen == 0) { |
38 | -+ /* Error set by SECKEY_SignatureLen */ |
39 | -+ return sigLen; |
40 | -+ } |
41 | -+ unsigned int maxSigLen; |
42 | -+ switch (pubk->keyType) { |
43 | -+ case rsaKey: |
44 | -+ case rsaPssKey: |
45 | -+ maxSigLen = (RSA_MAX_MODULUS_BITS + 7) / 8; |
46 | -+ break; |
47 | -+ case dsaKey: |
48 | -+ maxSigLen = DSA_MAX_SIGNATURE_LEN; |
49 | -+ break; |
50 | -+ case ecKey: |
51 | -+ maxSigLen = 2 * MAX_ECKEY_LEN; |
52 | -+ break; |
53 | -+ default: |
54 | -+ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); |
55 | -+ return 0; |
56 | -+ } |
57 | -+ if (sigLen > maxSigLen) { |
58 | -+ PORT_SetError(SEC_ERROR_INVALID_KEY); |
59 | -+ return 0; |
60 | -+ } |
61 | -+ return sigLen; |
62 | -+} |
63 | -+ |
64 | - /* |
65 | - * decode the ECDSA or DSA signature from it's DER wrapping. |
66 | - * The unwrapped/raw signature is placed in the buffer pointed |
67 | -@@ -174,38 +205,38 @@ |
68 | - unsigned int len) |
69 | - { |
70 | - SECItem *dsasig = NULL; /* also used for ECDSA */ |
71 | -- SECStatus rv = SECSuccess; |
72 | - |
73 | -- if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) && |
74 | -- (algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { |
75 | -- if (sig->len != len) { |
76 | -- PORT_SetError(SEC_ERROR_BAD_DER); |
77 | -- return SECFailure; |
78 | -+ /* Safety: Ensure algId is as expected and that signature size is within maxmimums */ |
79 | -+ if (algid == SEC_OID_ANSIX9_DSA_SIGNATURE) { |
80 | -+ if (len > DSA_MAX_SIGNATURE_LEN) { |
81 | -+ goto loser; |
82 | - } |
83 | -- |
84 | -- PORT_Memcpy(dsig, sig->data, sig->len); |
85 | -- return SECSuccess; |
86 | -+ } else if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { |
87 | -+ if (len > MAX_ECKEY_LEN * 2) { |
88 | -+ goto loser; |
89 | -+ } |
90 | -+ } else { |
91 | -+ goto loser; |
92 | - } |
93 | - |
94 | -- if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { |
95 | -- if (len > MAX_ECKEY_LEN * 2) { |
96 | -- PORT_SetError(SEC_ERROR_BAD_DER); |
97 | -- return SECFailure; |
98 | -- } |
99 | -+ /* Decode and pad to length */ |
100 | -+ dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); |
101 | -+ if (dsasig == NULL) { |
102 | -+ goto loser; |
103 | - } |
104 | -- dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); |
105 | -- |
106 | -- if ((dsasig == NULL) || (dsasig->len != len)) { |
107 | -- rv = SECFailure; |
108 | -- } else { |
109 | -- PORT_Memcpy(dsig, dsasig->data, dsasig->len); |
110 | -+ if (dsasig->len != len) { |
111 | -+ SECITEM_FreeItem(dsasig, PR_TRUE); |
112 | -+ goto loser; |
113 | - } |
114 | - |
115 | -- if (dsasig != NULL) |
116 | -- SECITEM_FreeItem(dsasig, PR_TRUE); |
117 | -- if (rv == SECFailure) |
118 | -- PORT_SetError(SEC_ERROR_BAD_DER); |
119 | -- return rv; |
120 | -+ PORT_Memcpy(dsig, dsasig->data, len); |
121 | -+ SECITEM_FreeItem(dsasig, PR_TRUE); |
122 | -+ |
123 | -+ return SECSuccess; |
124 | -+ |
125 | -+loser: |
126 | -+ PORT_SetError(SEC_ERROR_BAD_DER); |
127 | -+ return SECFailure; |
128 | - } |
129 | - |
130 | - const SEC_ASN1Template hashParameterTemplate[] = |
131 | -@@ -281,7 +312,7 @@ |
132 | - sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, |
133 | - const SECItem *param, SECOidTag *encalgp, SECOidTag *hashalg) |
134 | - { |
135 | -- int len; |
136 | -+ unsigned int len; |
137 | - PLArenaPool *arena; |
138 | - SECStatus rv; |
139 | - SECItem oid; |
140 | -@@ -466,48 +497,52 @@ |
141 | - cx->pkcs1RSADigestInfo = NULL; |
142 | - rv = SECSuccess; |
143 | - if (sig) { |
144 | -- switch (type) { |
145 | -- case rsaKey: |
146 | -- rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, |
147 | -- &cx->pkcs1RSADigestInfo, |
148 | -- &cx->pkcs1RSADigestInfoLen, |
149 | -- cx->key, |
150 | -- sig, wincx); |
151 | -- break; |
152 | -- case rsaPssKey: |
153 | -- sigLen = SECKEY_SignatureLen(key); |
154 | -- if (sigLen == 0) { |
155 | -- /* error set by SECKEY_SignatureLen */ |
156 | -- rv = SECFailure; |
157 | -+ rv = SECFailure; |
158 | -+ if (type == rsaKey) { |
159 | -+ rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, |
160 | -+ &cx->pkcs1RSADigestInfo, |
161 | -+ &cx->pkcs1RSADigestInfoLen, |
162 | -+ cx->key, |
163 | -+ sig, wincx); |
164 | -+ } else { |
165 | -+ sigLen = checkedSignatureLen(key); |
166 | -+ /* Check signature length is within limits */ |
167 | -+ if (sigLen == 0) { |
168 | -+ /* error set by checkedSignatureLen */ |
169 | -+ rv = SECFailure; |
170 | -+ goto loser; |
171 | -+ } |
172 | -+ if (sigLen > sizeof(cx->u)) { |
173 | -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
174 | -+ rv = SECFailure; |
175 | -+ goto loser; |
176 | -+ } |
177 | -+ switch (type) { |
178 | -+ case rsaPssKey: |
179 | -+ if (sig->len != sigLen) { |
180 | -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
181 | -+ rv = SECFailure; |
182 | -+ goto loser; |
183 | -+ } |
184 | -+ PORT_Memcpy(cx->u.buffer, sig->data, sigLen); |
185 | -+ rv = SECSuccess; |
186 | - break; |
187 | -- } |
188 | -- if (sig->len != sigLen) { |
189 | -- PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
190 | -+ case ecKey: |
191 | -+ case dsaKey: |
192 | -+ /* decodeECorDSASignature will check sigLen == sig->len after padding */ |
193 | -+ rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); |
194 | -+ break; |
195 | -+ default: |
196 | -+ /* Unreachable */ |
197 | - rv = SECFailure; |
198 | -- break; |
199 | -- } |
200 | -- PORT_Memcpy(cx->u.buffer, sig->data, sigLen); |
201 | -- break; |
202 | -- case dsaKey: |
203 | -- case ecKey: |
204 | -- sigLen = SECKEY_SignatureLen(key); |
205 | -- if (sigLen == 0) { |
206 | -- /* error set by SECKEY_SignatureLen */ |
207 | -- rv = SECFailure; |
208 | -- break; |
209 | -- } |
210 | -- rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); |
211 | -- break; |
212 | -- default: |
213 | -- rv = SECFailure; |
214 | -- PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); |
215 | -- break; |
216 | -+ goto loser; |
217 | -+ } |
218 | -+ } |
219 | -+ if (rv != SECSuccess) { |
220 | -+ goto loser; |
221 | - } |
222 | - } |
223 | - |
224 | -- if (rv) |
225 | -- goto loser; |
226 | -- |
227 | - /* check hash alg again, RSA may have changed it.*/ |
228 | - if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) { |
229 | - /* error set by HASH_GetHashTypeByOidTag */ |
230 | -@@ -650,11 +685,16 @@ |
231 | - switch (cx->key->keyType) { |
232 | - case ecKey: |
233 | - case dsaKey: |
234 | -- dsasig.data = cx->u.buffer; |
235 | -- dsasig.len = SECKEY_SignatureLen(cx->key); |
236 | -+ dsasig.len = checkedSignatureLen(cx->key); |
237 | - if (dsasig.len == 0) { |
238 | - return SECFailure; |
239 | - } |
240 | -+ if (dsasig.len > sizeof(cx->u)) { |
241 | -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
242 | -+ return SECFailure; |
243 | -+ } |
244 | -+ dsasig.data = cx->u.buffer; |
245 | -+ |
246 | - if (sig) { |
247 | - rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data, |
248 | - dsasig.len); |
249 | -@@ -686,8 +726,13 @@ |
250 | - } |
251 | - |
252 | - rsasig.data = cx->u.buffer; |
253 | -- rsasig.len = SECKEY_SignatureLen(cx->key); |
254 | -+ rsasig.len = checkedSignatureLen(cx->key); |
255 | - if (rsasig.len == 0) { |
256 | -+ /* Error set by checkedSignatureLen */ |
257 | -+ return SECFailure; |
258 | -+ } |
259 | -+ if (rsasig.len > sizeof(cx->u)) { |
260 | -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
261 | - return SECFailure; |
262 | - } |
263 | - if (sig) { |
264 | -@@ -749,7 +794,6 @@ |
265 | - SECStatus rv; |
266 | - VFYContext *cx; |
267 | - SECItem dsasig; /* also used for ECDSA */ |
268 | -- |
269 | - rv = SECFailure; |
270 | - |
271 | - cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); |
272 | -@@ -757,19 +801,25 @@ |
273 | - switch (key->keyType) { |
274 | - case rsaKey: |
275 | - rv = verifyPKCS1DigestInfo(cx, digest); |
276 | -+ /* Error (if any) set by verifyPKCS1DigestInfo */ |
277 | - break; |
278 | -- case dsaKey: |
279 | - case ecKey: |
280 | -+ case dsaKey: |
281 | - dsasig.data = cx->u.buffer; |
282 | -- dsasig.len = SECKEY_SignatureLen(cx->key); |
283 | -+ dsasig.len = checkedSignatureLen(cx->key); |
284 | - if (dsasig.len == 0) { |
285 | -+ /* Error set by checkedSignatureLen */ |
286 | -+ rv = SECFailure; |
287 | - break; |
288 | - } |
289 | -- if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx) != |
290 | -- SECSuccess) { |
291 | -+ if (dsasig.len > sizeof(cx->u)) { |
292 | - PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
293 | -- } else { |
294 | -- rv = SECSuccess; |
295 | -+ rv = SECFailure; |
296 | -+ break; |
297 | -+ } |
298 | -+ rv = PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx); |
299 | -+ if (rv != SECSuccess) { |
300 | -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
301 | - } |
302 | - break; |
303 | - default: |
304 | - |
305 | diff --git a/debian/patches/series b/debian/patches/series |
306 | index 64788bc..bac12de 100644 |
307 | --- a/debian/patches/series |
308 | +++ b/debian/patches/series |
309 | @@ -7,4 +7,3 @@ disable_fips_enabled_read.patch |
310 | set-tls1.2-as-minimum.patch |
311 | fix-ftbfs-s390x.patch |
312 | fix-ftbfs-glibc-invalid-oob-error.patch |
313 | -CVE-2021-43527.patch |
314 | diff --git a/nss/.hg_archival.txt b/nss/.hg_archival.txt |
315 | index 9a2c8a2..807d9fe 100644 |
316 | --- a/nss/.hg_archival.txt |
317 | +++ b/nss/.hg_archival.txt |
318 | @@ -1,4 +1,4 @@ |
319 | repo: 9949429068caa6bb8827a8ceeaa7c605d722f47f |
320 | -node: 3680dc580194cbe3bb1004d2f7741eebc3066d2c |
321 | -branch: NSS_3_68_BRANCH |
322 | -tag: NSS_3_68_RTM |
323 | +node: 78d2f4a3339fa41c274c5ea189f8060da9d3a463 |
324 | +branch: NSS_3_68_2_BRANCH |
325 | +tag: NSS_3_68_2_RTM |
326 | diff --git a/nss/gtests/certdb_gtest/decode_certs_unittest.cc b/nss/gtests/certdb_gtest/decode_certs_unittest.cc |
327 | index 405194e..3317ae8 100644 |
328 | --- a/nss/gtests/certdb_gtest/decode_certs_unittest.cc |
329 | +++ b/nss/gtests/certdb_gtest/decode_certs_unittest.cc |
330 | @@ -26,3 +26,16 @@ TEST_F(DecodeCertsTest, EmptyCertPackage) { |
331 | sizeof(emptyCertPackage))); |
332 | EXPECT_EQ(SEC_ERROR_BAD_DER, PR_GetError()); |
333 | } |
334 | + |
335 | +TEST_F(DecodeCertsTest, EmptySignedData) { |
336 | + // This represents a PKCS#7 ContentInfo of contentType |
337 | + // 1.2.840.113549.1.7.2 (signedData) with missing content. |
338 | + unsigned char emptySignedData[] = {0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, |
339 | + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, |
340 | + 0x02, 0x00, 0x00, 0x05, 0x00}; |
341 | + |
342 | + EXPECT_EQ(nullptr, |
343 | + CERT_DecodeCertFromPackage(reinterpret_cast<char*>(emptySignedData), |
344 | + sizeof(emptySignedData))); |
345 | + EXPECT_EQ(SEC_ERROR_BAD_DER, PR_GetError()); |
346 | +} |
347 | diff --git a/nss/gtests/mozpkix_gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp b/nss/gtests/mozpkix_gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp |
348 | index 58336df..c7e8236 100644 |
349 | --- a/nss/gtests/mozpkix_gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp |
350 | +++ b/nss/gtests/mozpkix_gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp |
351 | @@ -217,9 +217,13 @@ public: |
352 | const TestSignatureAlgorithm& signatureAlgorithm, |
353 | /*optional*/ const ByteString* certs = nullptr, |
354 | /*optional*/ OCSPResponseExtension* singleExtensions = nullptr, |
355 | - /*optional*/ OCSPResponseExtension* responseExtensions = nullptr) |
356 | + /*optional*/ OCSPResponseExtension* responseExtensions = nullptr, |
357 | + /*optional*/ DigestAlgorithm certIDHashAlgorithm = DigestAlgorithm::sha1, |
358 | + /*optional*/ ByteString certIDHashAlgorithmEncoded = ByteString()) |
359 | { |
360 | OCSPResponseContext context(certID, producedAt); |
361 | + context.certIDHashAlgorithm = certIDHashAlgorithm; |
362 | + context.certIDHashAlgorithmEncoded = certIDHashAlgorithmEncoded; |
363 | if (signerName) { |
364 | context.signerNameDER = CNToDERName(signerName); |
365 | EXPECT_FALSE(ENCODING_FAILED(context.signerNameDER)); |
366 | @@ -466,6 +470,72 @@ TEST_F(pkixocsp_VerifyEncodedResponse_successful, ct_extension) |
367 | trustDomain.signedCertificateTimestamps); |
368 | } |
369 | |
370 | +struct CertIDHashAlgorithm |
371 | +{ |
372 | + DigestAlgorithm hashAlgorithm; |
373 | + ByteString encodedHashAlgorithm; |
374 | + Result expectedResult; |
375 | +}; |
376 | + |
377 | +// python DottedOIDToCode.py --alg id-sha1 1.3.14.3.2.26 |
378 | +static const uint8_t alg_id_sha1[] = { |
379 | + 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a |
380 | +}; |
381 | +// python DottedOIDToCode.py --alg id-sha256 2.16.840.1.101.3.4.2.1 |
382 | +static const uint8_t alg_id_sha256[] = { |
383 | + 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 |
384 | +}; |
385 | +static const uint8_t not_an_encoded_hash_oid[] = { |
386 | + 0x01, 0x02, 0x03, 0x04 |
387 | +}; |
388 | + |
389 | +static const CertIDHashAlgorithm CERTID_HASH_ALGORITHMS[] = { |
390 | + { DigestAlgorithm::sha1, ByteString(), Success }, |
391 | + { DigestAlgorithm::sha256, ByteString(), Success }, |
392 | + { DigestAlgorithm::sha384, ByteString(), Success }, |
393 | + { DigestAlgorithm::sha512, ByteString(), Success }, |
394 | + { DigestAlgorithm::sha256, BytesToByteString(alg_id_sha1), |
395 | + Result::ERROR_OCSP_MALFORMED_RESPONSE }, |
396 | + { DigestAlgorithm::sha1, BytesToByteString(alg_id_sha256), |
397 | + Result::ERROR_OCSP_MALFORMED_RESPONSE }, |
398 | + { DigestAlgorithm::sha1, BytesToByteString(not_an_encoded_hash_oid), |
399 | + Result::ERROR_OCSP_MALFORMED_RESPONSE }, |
400 | +}; |
401 | + |
402 | +class pkixocsp_VerifyEncodedResponse_CertIDHashAlgorithm |
403 | + : public pkixocsp_VerifyEncodedResponse_successful |
404 | + , public ::testing::WithParamInterface<CertIDHashAlgorithm> |
405 | +{ |
406 | +}; |
407 | + |
408 | +TEST_P(pkixocsp_VerifyEncodedResponse_CertIDHashAlgorithm, CertIDHashAlgorithm) |
409 | +{ |
410 | + ByteString responseString( |
411 | + CreateEncodedOCSPSuccessfulResponse( |
412 | + OCSPResponseContext::good, *endEntityCertID, byKey, |
413 | + *rootKeyPair, oneDayBeforeNow, |
414 | + oneDayBeforeNow, &oneDayAfterNow, |
415 | + sha256WithRSAEncryption(), |
416 | + nullptr, |
417 | + nullptr, |
418 | + nullptr, |
419 | + GetParam().hashAlgorithm, |
420 | + GetParam().encodedHashAlgorithm)); |
421 | + Input response; |
422 | + ASSERT_EQ(Success, |
423 | + response.Init(responseString.data(), responseString.length())); |
424 | + bool expired; |
425 | + ASSERT_EQ(GetParam().expectedResult, |
426 | + VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, |
427 | + Now(), END_ENTITY_MAX_LIFETIME_IN_DAYS, |
428 | + response, expired)); |
429 | + ASSERT_FALSE(expired); |
430 | +} |
431 | + |
432 | +INSTANTIATE_TEST_SUITE_P(pkixocsp_VerifyEncodedResponse_CertIDHashAlgorithm, |
433 | + pkixocsp_VerifyEncodedResponse_CertIDHashAlgorithm, |
434 | + testing::ValuesIn(CERTID_HASH_ALGORITHMS)); |
435 | + |
436 | /////////////////////////////////////////////////////////////////////////////// |
437 | // indirect responses (signed by a delegated OCSP responder cert) |
438 | |
439 | diff --git a/nss/lib/cryptohi/secvfy.c b/nss/lib/cryptohi/secvfy.c |
440 | index 2540a54..1754584 100644 |
441 | --- a/nss/lib/cryptohi/secvfy.c |
442 | +++ b/nss/lib/cryptohi/secvfy.c |
443 | @@ -164,6 +164,37 @@ verifyPKCS1DigestInfo(const VFYContext *cx, const SECItem *digest) |
444 | PR_FALSE /*XXX: unsafeAllowMissingParameters*/); |
445 | } |
446 | |
447 | +static unsigned int |
448 | +checkedSignatureLen(const SECKEYPublicKey *pubk) |
449 | +{ |
450 | + unsigned int sigLen = SECKEY_SignatureLen(pubk); |
451 | + if (sigLen == 0) { |
452 | + /* Error set by SECKEY_SignatureLen */ |
453 | + return sigLen; |
454 | + } |
455 | + unsigned int maxSigLen; |
456 | + switch (pubk->keyType) { |
457 | + case rsaKey: |
458 | + case rsaPssKey: |
459 | + maxSigLen = (RSA_MAX_MODULUS_BITS + 7) / 8; |
460 | + break; |
461 | + case dsaKey: |
462 | + maxSigLen = DSA_MAX_SIGNATURE_LEN; |
463 | + break; |
464 | + case ecKey: |
465 | + maxSigLen = 2 * MAX_ECKEY_LEN; |
466 | + break; |
467 | + default: |
468 | + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); |
469 | + return 0; |
470 | + } |
471 | + if (sigLen > maxSigLen) { |
472 | + PORT_SetError(SEC_ERROR_INVALID_KEY); |
473 | + return 0; |
474 | + } |
475 | + return sigLen; |
476 | +} |
477 | + |
478 | /* |
479 | * decode the ECDSA or DSA signature from it's DER wrapping. |
480 | * The unwrapped/raw signature is placed in the buffer pointed |
481 | @@ -174,38 +205,38 @@ decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig, |
482 | unsigned int len) |
483 | { |
484 | SECItem *dsasig = NULL; /* also used for ECDSA */ |
485 | - SECStatus rv = SECSuccess; |
486 | |
487 | - if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) && |
488 | - (algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { |
489 | - if (sig->len != len) { |
490 | - PORT_SetError(SEC_ERROR_BAD_DER); |
491 | - return SECFailure; |
492 | + /* Safety: Ensure algId is as expected and that signature size is within maxmimums */ |
493 | + if (algid == SEC_OID_ANSIX9_DSA_SIGNATURE) { |
494 | + if (len > DSA_MAX_SIGNATURE_LEN) { |
495 | + goto loser; |
496 | } |
497 | - |
498 | - PORT_Memcpy(dsig, sig->data, sig->len); |
499 | - return SECSuccess; |
500 | - } |
501 | - |
502 | - if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { |
503 | + } else if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { |
504 | if (len > MAX_ECKEY_LEN * 2) { |
505 | - PORT_SetError(SEC_ERROR_BAD_DER); |
506 | - return SECFailure; |
507 | + goto loser; |
508 | } |
509 | - } |
510 | - dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); |
511 | - |
512 | - if ((dsasig == NULL) || (dsasig->len != len)) { |
513 | - rv = SECFailure; |
514 | } else { |
515 | - PORT_Memcpy(dsig, dsasig->data, dsasig->len); |
516 | + goto loser; |
517 | } |
518 | |
519 | - if (dsasig != NULL) |
520 | + /* Decode and pad to length */ |
521 | + dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); |
522 | + if (dsasig == NULL) { |
523 | + goto loser; |
524 | + } |
525 | + if (dsasig->len != len) { |
526 | SECITEM_FreeItem(dsasig, PR_TRUE); |
527 | - if (rv == SECFailure) |
528 | - PORT_SetError(SEC_ERROR_BAD_DER); |
529 | - return rv; |
530 | + goto loser; |
531 | + } |
532 | + |
533 | + PORT_Memcpy(dsig, dsasig->data, len); |
534 | + SECITEM_FreeItem(dsasig, PR_TRUE); |
535 | + |
536 | + return SECSuccess; |
537 | + |
538 | +loser: |
539 | + PORT_SetError(SEC_ERROR_BAD_DER); |
540 | + return SECFailure; |
541 | } |
542 | |
543 | const SEC_ASN1Template hashParameterTemplate[] = |
544 | @@ -281,7 +312,7 @@ SECStatus |
545 | sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, |
546 | const SECItem *param, SECOidTag *encalgp, SECOidTag *hashalg) |
547 | { |
548 | - int len; |
549 | + unsigned int len; |
550 | PLArenaPool *arena; |
551 | SECStatus rv; |
552 | SECItem oid; |
553 | @@ -466,48 +497,52 @@ vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, |
554 | cx->pkcs1RSADigestInfo = NULL; |
555 | rv = SECSuccess; |
556 | if (sig) { |
557 | - switch (type) { |
558 | - case rsaKey: |
559 | - rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, |
560 | - &cx->pkcs1RSADigestInfo, |
561 | - &cx->pkcs1RSADigestInfoLen, |
562 | - cx->key, |
563 | - sig, wincx); |
564 | - break; |
565 | - case rsaPssKey: |
566 | - sigLen = SECKEY_SignatureLen(key); |
567 | - if (sigLen == 0) { |
568 | - /* error set by SECKEY_SignatureLen */ |
569 | - rv = SECFailure; |
570 | + rv = SECFailure; |
571 | + if (type == rsaKey) { |
572 | + rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, |
573 | + &cx->pkcs1RSADigestInfo, |
574 | + &cx->pkcs1RSADigestInfoLen, |
575 | + cx->key, |
576 | + sig, wincx); |
577 | + } else { |
578 | + sigLen = checkedSignatureLen(key); |
579 | + /* Check signature length is within limits */ |
580 | + if (sigLen == 0) { |
581 | + /* error set by checkedSignatureLen */ |
582 | + rv = SECFailure; |
583 | + goto loser; |
584 | + } |
585 | + if (sigLen > sizeof(cx->u)) { |
586 | + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
587 | + rv = SECFailure; |
588 | + goto loser; |
589 | + } |
590 | + switch (type) { |
591 | + case rsaPssKey: |
592 | + if (sig->len != sigLen) { |
593 | + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
594 | + rv = SECFailure; |
595 | + goto loser; |
596 | + } |
597 | + PORT_Memcpy(cx->u.buffer, sig->data, sigLen); |
598 | + rv = SECSuccess; |
599 | break; |
600 | - } |
601 | - if (sig->len != sigLen) { |
602 | - PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
603 | - rv = SECFailure; |
604 | + case ecKey: |
605 | + case dsaKey: |
606 | + /* decodeECorDSASignature will check sigLen == sig->len after padding */ |
607 | + rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); |
608 | break; |
609 | - } |
610 | - PORT_Memcpy(cx->u.buffer, sig->data, sigLen); |
611 | - break; |
612 | - case dsaKey: |
613 | - case ecKey: |
614 | - sigLen = SECKEY_SignatureLen(key); |
615 | - if (sigLen == 0) { |
616 | - /* error set by SECKEY_SignatureLen */ |
617 | + default: |
618 | + /* Unreachable */ |
619 | rv = SECFailure; |
620 | - break; |
621 | - } |
622 | - rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); |
623 | - break; |
624 | - default: |
625 | - rv = SECFailure; |
626 | - PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); |
627 | - break; |
628 | + goto loser; |
629 | + } |
630 | + } |
631 | + if (rv != SECSuccess) { |
632 | + goto loser; |
633 | } |
634 | } |
635 | |
636 | - if (rv) |
637 | - goto loser; |
638 | - |
639 | /* check hash alg again, RSA may have changed it.*/ |
640 | if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) { |
641 | /* error set by HASH_GetHashTypeByOidTag */ |
642 | @@ -650,11 +685,16 @@ VFY_EndWithSignature(VFYContext *cx, SECItem *sig) |
643 | switch (cx->key->keyType) { |
644 | case ecKey: |
645 | case dsaKey: |
646 | - dsasig.data = cx->u.buffer; |
647 | - dsasig.len = SECKEY_SignatureLen(cx->key); |
648 | + dsasig.len = checkedSignatureLen(cx->key); |
649 | if (dsasig.len == 0) { |
650 | return SECFailure; |
651 | } |
652 | + if (dsasig.len > sizeof(cx->u)) { |
653 | + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
654 | + return SECFailure; |
655 | + } |
656 | + dsasig.data = cx->u.buffer; |
657 | + |
658 | if (sig) { |
659 | rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data, |
660 | dsasig.len); |
661 | @@ -686,8 +726,13 @@ VFY_EndWithSignature(VFYContext *cx, SECItem *sig) |
662 | } |
663 | |
664 | rsasig.data = cx->u.buffer; |
665 | - rsasig.len = SECKEY_SignatureLen(cx->key); |
666 | + rsasig.len = checkedSignatureLen(cx->key); |
667 | if (rsasig.len == 0) { |
668 | + /* Error set by checkedSignatureLen */ |
669 | + return SECFailure; |
670 | + } |
671 | + if (rsasig.len > sizeof(cx->u)) { |
672 | + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
673 | return SECFailure; |
674 | } |
675 | if (sig) { |
676 | @@ -749,7 +794,6 @@ vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, |
677 | SECStatus rv; |
678 | VFYContext *cx; |
679 | SECItem dsasig; /* also used for ECDSA */ |
680 | - |
681 | rv = SECFailure; |
682 | |
683 | cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); |
684 | @@ -757,19 +801,25 @@ vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, |
685 | switch (key->keyType) { |
686 | case rsaKey: |
687 | rv = verifyPKCS1DigestInfo(cx, digest); |
688 | + /* Error (if any) set by verifyPKCS1DigestInfo */ |
689 | break; |
690 | - case dsaKey: |
691 | case ecKey: |
692 | + case dsaKey: |
693 | dsasig.data = cx->u.buffer; |
694 | - dsasig.len = SECKEY_SignatureLen(cx->key); |
695 | + dsasig.len = checkedSignatureLen(cx->key); |
696 | if (dsasig.len == 0) { |
697 | + /* Error set by checkedSignatureLen */ |
698 | + rv = SECFailure; |
699 | break; |
700 | } |
701 | - if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx) != |
702 | - SECSuccess) { |
703 | + if (dsasig.len > sizeof(cx->u)) { |
704 | + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
705 | + rv = SECFailure; |
706 | + break; |
707 | + } |
708 | + rv = PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx); |
709 | + if (rv != SECSuccess) { |
710 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
711 | - } else { |
712 | - rv = SECSuccess; |
713 | } |
714 | break; |
715 | default: |
716 | diff --git a/nss/lib/mozpkix/include/pkix-test/pkixtestutil.h b/nss/lib/mozpkix/include/pkix-test/pkixtestutil.h |
717 | index 55c4354..70c0fee 100644 |
718 | --- a/nss/lib/mozpkix/include/pkix-test/pkixtestutil.h |
719 | +++ b/nss/lib/mozpkix/include/pkix-test/pkixtestutil.h |
720 | @@ -349,6 +349,14 @@ class OCSPResponseContext final { |
721 | OCSPResponseContext(const CertID& certID, std::time_t time); |
722 | |
723 | const CertID& certID; |
724 | + // What digest algorithm to use to produce issuerNameHash and issuerKeyHash. |
725 | + // Defaults to sha1. |
726 | + DigestAlgorithm certIDHashAlgorithm; |
727 | + // If non-empty, the sequence of bytes to use for hashAlgorithm when encoding |
728 | + // this response. If empty, the sequence of bytes corresponding to |
729 | + // certIDHashAlgorithm will be used. Defaults to empty. |
730 | + ByteString certIDHashAlgorithmEncoded; |
731 | + |
732 | // TODO(bug 980538): add a way to specify what certificates are included. |
733 | |
734 | // The fields below are in the order that they appear in an OCSP response. |
735 | diff --git a/nss/lib/mozpkix/include/pkix/pkixutil.h b/nss/lib/mozpkix/include/pkix/pkixutil.h |
736 | index ca5b5a2..b224aa1 100644 |
737 | --- a/nss/lib/mozpkix/include/pkix/pkixutil.h |
738 | +++ b/nss/lib/mozpkix/include/pkix/pkixutil.h |
739 | @@ -259,6 +259,20 @@ Result CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo, |
740 | #else |
741 | #error Unsupported compiler for MOZILLA_PKIX_UNREACHABLE_DEFAULT. |
742 | #endif |
743 | + |
744 | +inline size_t DigestAlgorithmToSizeInBytes(DigestAlgorithm digestAlgorithm) { |
745 | + switch (digestAlgorithm) { |
746 | + case DigestAlgorithm::sha1: |
747 | + return 160 / 8; |
748 | + case DigestAlgorithm::sha256: |
749 | + return 256 / 8; |
750 | + case DigestAlgorithm::sha384: |
751 | + return 384 / 8; |
752 | + case DigestAlgorithm::sha512: |
753 | + return 512 / 8; |
754 | + MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM |
755 | + } |
756 | +} |
757 | } |
758 | } // namespace mozilla::pkix |
759 | |
760 | diff --git a/nss/lib/mozpkix/lib/pkixocsp.cpp b/nss/lib/mozpkix/lib/pkixocsp.cpp |
761 | index a811544..d725e55 100644 |
762 | --- a/nss/lib/mozpkix/lib/pkixocsp.cpp |
763 | +++ b/nss/lib/mozpkix/lib/pkixocsp.cpp |
764 | @@ -28,12 +28,6 @@ |
765 | #include "mozpkix/pkixcheck.h" |
766 | #include "mozpkix/pkixutil.h" |
767 | |
768 | -namespace { |
769 | - |
770 | -const size_t SHA1_DIGEST_LENGTH = 160 / 8; |
771 | - |
772 | -} // namespace |
773 | - |
774 | namespace mozilla { namespace pkix { |
775 | |
776 | // These values correspond to the tag values in the ASN.1 CertStatus |
777 | @@ -181,10 +175,12 @@ static inline Result MatchCertID(Reader& input, |
778 | const Context& context, |
779 | /*out*/ bool& match); |
780 | static Result MatchKeyHash(TrustDomain& trustDomain, |
781 | + DigestAlgorithm hashAlgorithm, |
782 | Input issuerKeyHash, |
783 | Input issuerSubjectPublicKeyInfo, |
784 | /*out*/ bool& match); |
785 | static Result KeyHash(TrustDomain& trustDomain, |
786 | + DigestAlgorithm hashAlgorithm, |
787 | Input subjectPublicKeyInfo, |
788 | /*out*/ uint8_t* hashBuf, size_t hashBufSize); |
789 | |
790 | @@ -213,7 +209,7 @@ MatchResponderID(TrustDomain& trustDomain, |
791 | if (rv != Success) { |
792 | return rv; |
793 | } |
794 | - return MatchKeyHash(trustDomain, keyHash, |
795 | + return MatchKeyHash(trustDomain, DigestAlgorithm::sha1, keyHash, |
796 | potentialSignerSubjectPublicKeyInfo, match); |
797 | } |
798 | |
799 | @@ -741,36 +737,36 @@ MatchCertID(Reader& input, const Context& context, /*out*/ bool& match) |
800 | return Success; |
801 | } |
802 | |
803 | - // TODO: support SHA-2 hashes. |
804 | - |
805 | - if (hashAlgorithm != DigestAlgorithm::sha1) { |
806 | - // Again, not interested in this response. Consume input, return success. |
807 | - input.SkipToEnd(); |
808 | - return Success; |
809 | - } |
810 | - |
811 | - if (issuerNameHash.GetLength() != SHA1_DIGEST_LENGTH) { |
812 | + size_t hashAlgorithmLength = DigestAlgorithmToSizeInBytes(hashAlgorithm); |
813 | + if (issuerNameHash.GetLength() != hashAlgorithmLength) { |
814 | return Result::ERROR_OCSP_MALFORMED_RESPONSE; |
815 | } |
816 | |
817 | // From http://tools.ietf.org/html/rfc6960#section-4.1.1: |
818 | // "The hash shall be calculated over the DER encoding of the |
819 | // issuer's name field in the certificate being checked." |
820 | - uint8_t hashBuf[SHA1_DIGEST_LENGTH]; |
821 | + uint8_t hashBuf[MAX_DIGEST_SIZE_IN_BYTES]; |
822 | + if (hashAlgorithmLength > sizeof(hashBuf)) { |
823 | + return Result::FATAL_ERROR_LIBRARY_FAILURE; |
824 | + } |
825 | rv = context.trustDomain.DigestBuf(context.certID.issuer, |
826 | - DigestAlgorithm::sha1, hashBuf, |
827 | - sizeof(hashBuf)); |
828 | + hashAlgorithm, hashBuf, |
829 | + hashAlgorithmLength); |
830 | + if (rv != Success) { |
831 | + return rv; |
832 | + } |
833 | + Input computed; |
834 | + rv = computed.Init(hashBuf, hashAlgorithmLength); |
835 | if (rv != Success) { |
836 | return rv; |
837 | } |
838 | - Input computed(hashBuf); |
839 | if (!InputsAreEqual(computed, issuerNameHash)) { |
840 | // Again, not interested in this response. Consume input, return success. |
841 | input.SkipToEnd(); |
842 | return Success; |
843 | } |
844 | |
845 | - return MatchKeyHash(context.trustDomain, issuerKeyHash, |
846 | + return MatchKeyHash(context.trustDomain, hashAlgorithm, issuerKeyHash, |
847 | context.certID.issuerSubjectPublicKeyInfo, match); |
848 | } |
849 | |
850 | @@ -784,30 +780,53 @@ MatchCertID(Reader& input, const Context& context, /*out*/ bool& match) |
851 | // -- BIT STRING subjectPublicKey [excluding |
852 | // -- the tag, length, and number of unused |
853 | // -- bits] in the responder's certificate) |
854 | +// |
855 | +// From https://datatracker.ietf.org/doc/html/rfc6960#section-4.1.1: |
856 | +// CertID ::= SEQUENCE { |
857 | +// hashAlgorithm AlgorithmIdentifier, |
858 | +// issuerNameHash OCTET STRING, -- Hash of issuer's DN |
859 | +// issuerKeyHash OCTET STRING, -- Hash of issuer's public key |
860 | +// serialNumber CertificateSerialNumber } |
861 | +// ... |
862 | +// o hashAlgorithm is the hash algorithm used to generate the |
863 | +// issuerNameHash and issuerKeyHash values. |
864 | +// ... |
865 | +// o issuerKeyHash is the hash of the issuer's public key. The hash |
866 | +// shall be calculated over the value (excluding tag and length) of |
867 | +// the subject public key field in the issuer's certificate. |
868 | static Result |
869 | -MatchKeyHash(TrustDomain& trustDomain, Input keyHash, |
870 | - const Input subjectPublicKeyInfo, /*out*/ bool& match) |
871 | +MatchKeyHash(TrustDomain& trustDomain, DigestAlgorithm hashAlgorithm, |
872 | + Input keyHash, const Input subjectPublicKeyInfo, |
873 | + /*out*/ bool& match) |
874 | { |
875 | - if (keyHash.GetLength() != SHA1_DIGEST_LENGTH) { |
876 | + size_t hashLength = DigestAlgorithmToSizeInBytes(hashAlgorithm); |
877 | + if (keyHash.GetLength() != hashLength) { |
878 | return Result::ERROR_OCSP_MALFORMED_RESPONSE; |
879 | } |
880 | - uint8_t hashBuf[SHA1_DIGEST_LENGTH]; |
881 | - Result rv = KeyHash(trustDomain, subjectPublicKeyInfo, hashBuf, |
882 | - sizeof hashBuf); |
883 | + uint8_t hashBuf[MAX_DIGEST_SIZE_IN_BYTES]; |
884 | + if (hashLength > MAX_DIGEST_SIZE_IN_BYTES) { |
885 | + return Result::FATAL_ERROR_LIBRARY_FAILURE; |
886 | + } |
887 | + Result rv = KeyHash(trustDomain, hashAlgorithm, subjectPublicKeyInfo, |
888 | + hashBuf, hashLength); |
889 | + if (rv != Success) { |
890 | + return rv; |
891 | + } |
892 | + Input computed; |
893 | + rv = computed.Init(hashBuf, hashLength); |
894 | if (rv != Success) { |
895 | return rv; |
896 | } |
897 | - Input computed(hashBuf); |
898 | match = InputsAreEqual(computed, keyHash); |
899 | return Success; |
900 | } |
901 | |
902 | -// TODO(bug 966856): support SHA-2 hashes |
903 | Result |
904 | -KeyHash(TrustDomain& trustDomain, const Input subjectPublicKeyInfo, |
905 | - /*out*/ uint8_t* hashBuf, size_t hashBufSize) |
906 | +KeyHash(TrustDomain& trustDomain, DigestAlgorithm hashAlgorithm, |
907 | + const Input subjectPublicKeyInfo, /*out*/ uint8_t* hashBuf, |
908 | + size_t hashBufSize) |
909 | { |
910 | - if (!hashBuf || hashBufSize != SHA1_DIGEST_LENGTH) { |
911 | + if (!hashBuf || hashBufSize != DigestAlgorithmToSizeInBytes(hashAlgorithm)) { |
912 | return Result::FATAL_ERROR_LIBRARY_FAILURE; |
913 | } |
914 | |
915 | @@ -840,8 +859,8 @@ KeyHash(TrustDomain& trustDomain, const Input subjectPublicKeyInfo, |
916 | return rv; |
917 | } |
918 | |
919 | - return trustDomain.DigestBuf(subjectPublicKey, DigestAlgorithm::sha1, |
920 | - hashBuf, hashBufSize); |
921 | + return trustDomain.DigestBuf(subjectPublicKey, hashAlgorithm, hashBuf, |
922 | + hashBufSize); |
923 | } |
924 | |
925 | Result |
926 | @@ -921,8 +940,6 @@ CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID, |
927 | // and thus more likely to fit within the 255 byte limit for OCSP GET that |
928 | // is specified in RFC 5019 Section 5. |
929 | |
930 | - // Bug 966856: Add the id-pkix-ocsp-pref-sig-algs extension. |
931 | - |
932 | // Since we don't know whether the OCSP responder supports anything other |
933 | // than SHA-1, we have no choice but to use SHA-1 for issuerNameHash and |
934 | // issuerKeyHash. |
935 | @@ -986,7 +1003,8 @@ CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID, |
936 | // reqCert.issuerKeyHash (OCTET STRING) |
937 | *d++ = 0x04; |
938 | *d++ = hashLen; |
939 | - rv = KeyHash(trustDomain, certID.issuerSubjectPublicKeyInfo, d, hashLen); |
940 | + rv = KeyHash(trustDomain, DigestAlgorithm::sha1, |
941 | + certID.issuerSubjectPublicKeyInfo, d, hashLen); |
942 | if (rv != Success) { |
943 | return rv; |
944 | } |
945 | diff --git a/nss/lib/mozpkix/lib/pkixverify.cpp b/nss/lib/mozpkix/lib/pkixverify.cpp |
946 | index 8ceb2c1..bec570d 100644 |
947 | --- a/nss/lib/mozpkix/lib/pkixverify.cpp |
948 | +++ b/nss/lib/mozpkix/lib/pkixverify.cpp |
949 | @@ -43,14 +43,7 @@ DigestSignedData(TrustDomain& trustDomain, |
950 | return Result::ERROR_BAD_DER; |
951 | } |
952 | |
953 | - size_t digestLen; |
954 | - switch (signedDigest.digestAlgorithm) { |
955 | - case DigestAlgorithm::sha512: digestLen = 512 / 8; break; |
956 | - case DigestAlgorithm::sha384: digestLen = 384 / 8; break; |
957 | - case DigestAlgorithm::sha256: digestLen = 256 / 8; break; |
958 | - case DigestAlgorithm::sha1: digestLen = 160 / 8; break; |
959 | - MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM |
960 | - } |
961 | + size_t digestLen = DigestAlgorithmToSizeInBytes(signedDigest.digestAlgorithm); |
962 | assert(digestLen <= sizeof(digestBuf)); |
963 | |
964 | rv = trustDomain.DigestBuf(signedData.data, signedDigest.digestAlgorithm, |
965 | diff --git a/nss/lib/mozpkix/test-lib/pkixtestutil.cpp b/nss/lib/mozpkix/test-lib/pkixtestutil.cpp |
966 | index b1b89c0..306f7a0 100644 |
967 | --- a/nss/lib/mozpkix/test-lib/pkixtestutil.cpp |
968 | +++ b/nss/lib/mozpkix/test-lib/pkixtestutil.cpp |
969 | @@ -156,6 +156,8 @@ OCSPResponseExtension::OCSPResponseExtension() |
970 | |
971 | OCSPResponseContext::OCSPResponseContext(const CertID& aCertID, time_t time) |
972 | : certID(aCertID) |
973 | + , certIDHashAlgorithm(DigestAlgorithm::sha1) |
974 | + , certIDHashAlgorithmEncoded(ByteString()) |
975 | , responseStatus(successful) |
976 | , skipResponseBytes(false) |
977 | , producedAt(time) |
978 | @@ -184,25 +186,26 @@ static ByteString CertID(OCSPResponseContext& context); |
979 | static ByteString CertStatus(OCSPResponseContext& context); |
980 | |
981 | static ByteString |
982 | -SHA1(const ByteString& toHash) |
983 | +HASH(const ByteString& toHash, DigestAlgorithm digestAlgorithm) |
984 | { |
985 | - uint8_t digestBuf[20]; |
986 | + uint8_t digestBuf[MAX_DIGEST_SIZE_IN_BYTES]; |
987 | Input input; |
988 | if (input.Init(toHash.data(), toHash.length()) != Success) { |
989 | abort(); |
990 | } |
991 | - Result rv = TestDigestBuf(input, DigestAlgorithm::sha1, digestBuf, |
992 | - sizeof(digestBuf)); |
993 | + size_t digestLen = DigestAlgorithmToSizeInBytes(digestAlgorithm); |
994 | + assert(digestLen <= sizeof(digestBuf)); |
995 | + Result rv = TestDigestBuf(input, digestAlgorithm, digestBuf, digestLen); |
996 | if (rv != Success) { |
997 | abort(); |
998 | } |
999 | - return ByteString(digestBuf, sizeof(digestBuf)); |
1000 | + return ByteString(digestBuf, digestLen); |
1001 | } |
1002 | |
1003 | static ByteString |
1004 | -HashedOctetString(const ByteString& bytes) |
1005 | +HashedOctetString(const ByteString& bytes, DigestAlgorithm digestAlgorithm) |
1006 | { |
1007 | - ByteString digest(SHA1(bytes)); |
1008 | + ByteString digest(HASH(bytes, digestAlgorithm)); |
1009 | if (ENCODING_FAILED(digest)) { |
1010 | return ByteString(); |
1011 | } |
1012 | @@ -993,7 +996,7 @@ ResponderID(OCSPResponseContext& context) |
1013 | ByteString |
1014 | KeyHash(const ByteString& subjectPublicKey) |
1015 | { |
1016 | - return HashedOctetString(subjectPublicKey); |
1017 | + return HashedOctetString(subjectPublicKey, DigestAlgorithm::sha1); |
1018 | } |
1019 | |
1020 | // SingleResponse ::= SEQUENCE { |
1021 | @@ -1050,7 +1053,7 @@ CertID(OCSPResponseContext& context) |
1022 | { |
1023 | ByteString issuerName(context.certID.issuer.UnsafeGetData(), |
1024 | context.certID.issuer.GetLength()); |
1025 | - ByteString issuerNameHash(HashedOctetString(issuerName)); |
1026 | + ByteString issuerNameHash(HashedOctetString(issuerName, context.certIDHashAlgorithm)); |
1027 | if (ENCODING_FAILED(issuerNameHash)) { |
1028 | return ByteString(); |
1029 | } |
1030 | @@ -1074,8 +1077,8 @@ CertID(OCSPResponseContext& context) |
1031 | != Success) { |
1032 | return ByteString(); |
1033 | } |
1034 | - issuerKeyHash = KeyHash(ByteString(subjectPublicKey.UnsafeGetData(), |
1035 | - subjectPublicKey.GetLength())); |
1036 | + issuerKeyHash = HashedOctetString(ByteString(subjectPublicKey.UnsafeGetData(), |
1037 | + subjectPublicKey.GetLength()), context.certIDHashAlgorithm); |
1038 | if (ENCODING_FAILED(issuerKeyHash)) { |
1039 | return ByteString(); |
1040 | } |
1041 | @@ -1089,9 +1092,39 @@ CertID(OCSPResponseContext& context) |
1042 | static const uint8_t alg_id_sha1[] = { |
1043 | 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a |
1044 | }; |
1045 | + // python DottedOIDToCode.py --alg id-sha256 2.16.840.1.101.3.4.2.1 |
1046 | + static const uint8_t alg_id_sha256[] = { |
1047 | + 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 |
1048 | + }; |
1049 | + // python DottedOIDToCode.py --alg id-sha384 2.16.840.1.101.3.4.2.2 |
1050 | + static const uint8_t alg_id_sha384[] = { |
1051 | + 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 |
1052 | + }; |
1053 | + // python DottedOIDToCode.py --alg id-sha512 2.16.840.1.101.3.4.2.3 |
1054 | + static const uint8_t alg_id_sha512[] = { |
1055 | + 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 |
1056 | + }; |
1057 | |
1058 | ByteString value; |
1059 | - value.append(alg_id_sha1, sizeof(alg_id_sha1)); |
1060 | + if (!context.certIDHashAlgorithmEncoded.empty()) { |
1061 | + value.append(context.certIDHashAlgorithmEncoded); |
1062 | + } else { |
1063 | + switch (context.certIDHashAlgorithm) { |
1064 | + case DigestAlgorithm::sha1: |
1065 | + value.append(alg_id_sha1, sizeof(alg_id_sha1)); |
1066 | + break; |
1067 | + case DigestAlgorithm::sha256: |
1068 | + value.append(alg_id_sha256, sizeof(alg_id_sha256)); |
1069 | + break; |
1070 | + case DigestAlgorithm::sha384: |
1071 | + value.append(alg_id_sha384, sizeof(alg_id_sha384)); |
1072 | + break; |
1073 | + case DigestAlgorithm::sha512: |
1074 | + value.append(alg_id_sha512, sizeof(alg_id_sha512)); |
1075 | + break; |
1076 | + MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM |
1077 | + } |
1078 | + } |
1079 | value.append(issuerNameHash); |
1080 | value.append(issuerKeyHash); |
1081 | value.append(serialNumber); |
1082 | diff --git a/nss/lib/nss/nss.h b/nss/lib/nss/nss.h |
1083 | index 5d372e7..c87fa1e 100644 |
1084 | --- a/nss/lib/nss/nss.h |
1085 | +++ b/nss/lib/nss/nss.h |
1086 | @@ -22,10 +22,10 @@ |
1087 | * The format of the version string should be |
1088 | * "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]" |
1089 | */ |
1090 | -#define NSS_VERSION "3.68" _NSS_CUSTOMIZED |
1091 | +#define NSS_VERSION "3.68.2" _NSS_CUSTOMIZED |
1092 | #define NSS_VMAJOR 3 |
1093 | #define NSS_VMINOR 68 |
1094 | -#define NSS_VPATCH 0 |
1095 | +#define NSS_VPATCH 2 |
1096 | #define NSS_VBUILD 0 |
1097 | #define NSS_BETA PR_FALSE |
1098 | |
1099 | diff --git a/nss/lib/pkcs7/certread.c b/nss/lib/pkcs7/certread.c |
1100 | index 3091f99..15094f2 100644 |
1101 | --- a/nss/lib/pkcs7/certread.c |
1102 | +++ b/nss/lib/pkcs7/certread.c |
1103 | @@ -139,6 +139,11 @@ SEC_ReadPKCS7Certs(SECItem *pkcs7Item, CERTImportCertificateFunc f, void *arg) |
1104 | goto done; |
1105 | } |
1106 | |
1107 | + if (contentInfo.content.signedData == NULL) { |
1108 | + PORT_SetError(SEC_ERROR_BAD_DER); |
1109 | + goto done; |
1110 | + } |
1111 | + |
1112 | rv = SECSuccess; |
1113 | |
1114 | certs = contentInfo.content.signedData->certificates; |
1115 | diff --git a/nss/lib/softoken/softkver.h b/nss/lib/softoken/softkver.h |
1116 | index 349373e..f3506b6 100644 |
1117 | --- a/nss/lib/softoken/softkver.h |
1118 | +++ b/nss/lib/softoken/softkver.h |
1119 | @@ -17,10 +17,10 @@ |
1120 | * The format of the version string should be |
1121 | * "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]" |
1122 | */ |
1123 | -#define SOFTOKEN_VERSION "3.68" SOFTOKEN_ECC_STRING |
1124 | +#define SOFTOKEN_VERSION "3.68.2" SOFTOKEN_ECC_STRING |
1125 | #define SOFTOKEN_VMAJOR 3 |
1126 | #define SOFTOKEN_VMINOR 68 |
1127 | -#define SOFTOKEN_VPATCH 0 |
1128 | +#define SOFTOKEN_VPATCH 2 |
1129 | #define SOFTOKEN_VBUILD 0 |
1130 | #define SOFTOKEN_BETA PR_FALSE |
1131 | |
1132 | diff --git a/nss/lib/util/nssutil.h b/nss/lib/util/nssutil.h |
1133 | index 21cdbf6..28e0f1e 100644 |
1134 | --- a/nss/lib/util/nssutil.h |
1135 | +++ b/nss/lib/util/nssutil.h |
1136 | @@ -19,10 +19,10 @@ |
1137 | * The format of the version string should be |
1138 | * "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]" |
1139 | */ |
1140 | -#define NSSUTIL_VERSION "3.68" |
1141 | +#define NSSUTIL_VERSION "3.68.2" |
1142 | #define NSSUTIL_VMAJOR 3 |
1143 | #define NSSUTIL_VMINOR 68 |
1144 | -#define NSSUTIL_VPATCH 0 |
1145 | +#define NSSUTIL_VPATCH 2 |
1146 | #define NSSUTIL_VBUILD 0 |
1147 | #define NSSUTIL_BETA PR_FALSE |
1148 |
Thanks Athos. The update looks good, the package in the PPA installs/upgrades fine, nothing suspicious showed up in the build logs, and according to upstream no rebuild of reverse dependencies is needed indeed.
The only thing that we could do to improve the changelog entry, in my opinion, is mentioning the fix of the CVE-2021-43527 which according to the upstream is a critical issue:
https:/ /www.mozilla. org/en- US/security/ advisories/ mfsa2021- 51/
This is not a blocker, it is just a plus. Feel free to ignore this if you believe it is not needed. Also let me know if you need a sponsor for this upload.