|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
3 /* Copyright 2013 Mozilla Foundation |
|
4 * |
|
5 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 * you may not use this file except in compliance with the License. |
|
7 * You may obtain a copy of the License at |
|
8 * |
|
9 * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 * |
|
11 * Unless required by applicable law or agreed to in writing, software |
|
12 * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 * See the License for the specific language governing permissions and |
|
15 * limitations under the License. |
|
16 */ |
|
17 |
|
18 #include "pkix/pkix.h" |
|
19 |
|
20 #include <limits> |
|
21 #include <stdint.h> |
|
22 |
|
23 #include "cert.h" |
|
24 #include "cryptohi.h" |
|
25 #include "prerror.h" |
|
26 #include "secerr.h" |
|
27 |
|
28 namespace mozilla { namespace pkix { |
|
29 |
|
30 SECStatus |
|
31 VerifySignedData(const CERTSignedData* sd, const CERTCertificate* cert, |
|
32 void* pkcs11PinArg) |
|
33 { |
|
34 if (!sd || !sd->data.data || !sd->signatureAlgorithm.algorithm.data || |
|
35 !sd->signature.data || !cert) { |
|
36 PR_NOT_REACHED("invalid args to VerifySignedData"); |
|
37 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); |
|
38 return SECFailure; |
|
39 } |
|
40 |
|
41 // See bug 921585. |
|
42 if (sd->data.len > static_cast<unsigned int>(std::numeric_limits<int>::max())) { |
|
43 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); |
|
44 return SECFailure; |
|
45 } |
|
46 |
|
47 // convert sig->len from bit counts to byte count. |
|
48 SECItem sig = sd->signature; |
|
49 DER_ConvertBitString(&sig); |
|
50 |
|
51 // Use SECKEY_ExtractPublicKey instead of CERT_ExtractPublicKey because |
|
52 // CERT_ExtractPublicKey would try to do (EC)DSA parameter inheritance, using |
|
53 // the classic (wrong) NSS path building logic. We intentionally do not |
|
54 // support parameter inheritance. |
|
55 ScopedSECKEYPublicKey |
|
56 pubKey(SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo)); |
|
57 if (!pubKey) { |
|
58 return SECFailure; |
|
59 } |
|
60 |
|
61 SECOidTag hashAlg; |
|
62 if (VFY_VerifyDataWithAlgorithmID(sd->data.data, static_cast<int>(sd->data.len), |
|
63 pubKey.get(), &sig, &sd->signatureAlgorithm, |
|
64 &hashAlg, pkcs11PinArg) != SECSuccess) { |
|
65 return SECFailure; |
|
66 } |
|
67 |
|
68 // TODO: Ideally, we would do this check before we call |
|
69 // VFY_VerifyDataWithAlgorithmID. But, VFY_VerifyDataWithAlgorithmID gives us |
|
70 // the hash algorithm so it is more convenient to do things in this order. |
|
71 uint32_t policy; |
|
72 if (NSS_GetAlgorithmPolicy(hashAlg, &policy) != SECSuccess) { |
|
73 return SECFailure; |
|
74 } |
|
75 |
|
76 // XXX: I'm not sure why there isn't NSS_USE_ALG_IN_SSL_SIGNATURE, but there |
|
77 // isn't. Since we don't know the context in which we're being called, be as |
|
78 // strict as we can be given the NSS API that is available. |
|
79 static const uint32_t requiredPolicy = NSS_USE_ALG_IN_CERT_SIGNATURE | |
|
80 NSS_USE_ALG_IN_CMS_SIGNATURE; |
|
81 if ((policy & requiredPolicy) != requiredPolicy) { |
|
82 PR_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 0); |
|
83 return SECFailure; |
|
84 } |
|
85 |
|
86 return SECSuccess; |
|
87 } |
|
88 |
|
89 } } // namespace mozilla::pkix |