/src/mozilla-central/security/pkix/lib/pkixnss.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | /* This code is made available to you under your choice of the following sets |
4 | | * of licensing terms: |
5 | | */ |
6 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
7 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
8 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
9 | | */ |
10 | | /* Copyright 2013 Mozilla Contributors |
11 | | * |
12 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
13 | | * you may not use this file except in compliance with the License. |
14 | | * You may obtain a copy of the License at |
15 | | * |
16 | | * http://www.apache.org/licenses/LICENSE-2.0 |
17 | | * |
18 | | * Unless required by applicable law or agreed to in writing, software |
19 | | * distributed under the License is distributed on an "AS IS" BASIS, |
20 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
21 | | * See the License for the specific language governing permissions and |
22 | | * limitations under the License. |
23 | | */ |
24 | | |
25 | | #include "pkix/pkixnss.h" |
26 | | |
27 | | #include <limits> |
28 | | |
29 | | #include "cryptohi.h" |
30 | | #include "keyhi.h" |
31 | | #include "pk11pub.h" |
32 | | #include "pkix/pkix.h" |
33 | | #include "pkixutil.h" |
34 | | #include "ScopedPtr.h" |
35 | | #include "secerr.h" |
36 | | #include "sslerr.h" |
37 | | |
38 | | namespace mozilla { namespace pkix { |
39 | | |
40 | | namespace { |
41 | | |
42 | | Result |
43 | | VerifySignedDigest(const SignedDigest& sd, |
44 | | Input subjectPublicKeyInfo, |
45 | | SECOidTag pubKeyAlg, |
46 | | void* pkcs11PinArg) |
47 | 0 | { |
48 | 0 | SECOidTag digestAlg; |
49 | 0 | switch (sd.digestAlgorithm) { |
50 | 0 | case DigestAlgorithm::sha512: digestAlg = SEC_OID_SHA512; break; |
51 | 0 | case DigestAlgorithm::sha384: digestAlg = SEC_OID_SHA384; break; |
52 | 0 | case DigestAlgorithm::sha256: digestAlg = SEC_OID_SHA256; break; |
53 | 0 | case DigestAlgorithm::sha1: digestAlg = SEC_OID_SHA1; break; |
54 | 0 | MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM |
55 | 0 | } |
56 | 0 | |
57 | 0 | SECItem subjectPublicKeyInfoSECItem = |
58 | 0 | UnsafeMapInputToSECItem(subjectPublicKeyInfo); |
59 | 0 | ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo> |
60 | 0 | spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem)); |
61 | 0 | if (!spki) { |
62 | 0 | return MapPRErrorCodeToResult(PR_GetError()); |
63 | 0 | } |
64 | 0 | ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey> |
65 | 0 | pubKey(SECKEY_ExtractPublicKey(spki.get())); |
66 | 0 | if (!pubKey) { |
67 | 0 | return MapPRErrorCodeToResult(PR_GetError()); |
68 | 0 | } |
69 | 0 | |
70 | 0 | SECItem digestSECItem(UnsafeMapInputToSECItem(sd.digest)); |
71 | 0 | SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature)); |
72 | 0 | SECStatus srv = VFY_VerifyDigestDirect(&digestSECItem, pubKey.get(), |
73 | 0 | &signatureSECItem, pubKeyAlg, |
74 | 0 | digestAlg, pkcs11PinArg); |
75 | 0 | if (srv != SECSuccess) { |
76 | 0 | return MapPRErrorCodeToResult(PR_GetError()); |
77 | 0 | } |
78 | 0 | |
79 | 0 | return Success; |
80 | 0 | } |
81 | | |
82 | | } // namespace |
83 | | |
84 | | Result |
85 | | VerifyRSAPKCS1SignedDigestNSS(const SignedDigest& sd, |
86 | | Input subjectPublicKeyInfo, |
87 | | void* pkcs11PinArg) |
88 | 0 | { |
89 | 0 | return VerifySignedDigest(sd, subjectPublicKeyInfo, |
90 | 0 | SEC_OID_PKCS1_RSA_ENCRYPTION, pkcs11PinArg); |
91 | 0 | } |
92 | | |
93 | | Result |
94 | | VerifyECDSASignedDigestNSS(const SignedDigest& sd, |
95 | | Input subjectPublicKeyInfo, |
96 | | void* pkcs11PinArg) |
97 | 0 | { |
98 | 0 | return VerifySignedDigest(sd, subjectPublicKeyInfo, |
99 | 0 | SEC_OID_ANSIX962_EC_PUBLIC_KEY, pkcs11PinArg); |
100 | 0 | } |
101 | | |
102 | | Result |
103 | | DigestBufNSS(Input item, |
104 | | DigestAlgorithm digestAlg, |
105 | | /*out*/ uint8_t* digestBuf, |
106 | | size_t digestBufLen) |
107 | 0 | { |
108 | 0 | SECOidTag oid; |
109 | 0 | size_t bits; |
110 | 0 | switch (digestAlg) { |
111 | 0 | case DigestAlgorithm::sha512: oid = SEC_OID_SHA512; bits = 512; break; |
112 | 0 | case DigestAlgorithm::sha384: oid = SEC_OID_SHA384; bits = 384; break; |
113 | 0 | case DigestAlgorithm::sha256: oid = SEC_OID_SHA256; bits = 256; break; |
114 | 0 | case DigestAlgorithm::sha1: oid = SEC_OID_SHA1; bits = 160; break; |
115 | 0 | MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM |
116 | 0 | } |
117 | 0 | if (digestBufLen != bits / 8) { |
118 | 0 | return Result::FATAL_ERROR_INVALID_ARGS; |
119 | 0 | } |
120 | 0 | |
121 | 0 | SECItem itemSECItem = UnsafeMapInputToSECItem(item); |
122 | 0 | if (itemSECItem.len > |
123 | 0 | static_cast<decltype(itemSECItem.len)>( |
124 | 0 | std::numeric_limits<int32_t>::max())) { |
125 | 0 | PR_NOT_REACHED("large items should not be possible here"); |
126 | 0 | return Result::FATAL_ERROR_INVALID_ARGS; |
127 | 0 | } |
128 | 0 | SECStatus srv = PK11_HashBuf(oid, digestBuf, itemSECItem.data, |
129 | 0 | static_cast<int32_t>(itemSECItem.len)); |
130 | 0 | if (srv != SECSuccess) { |
131 | 0 | return MapPRErrorCodeToResult(PR_GetError()); |
132 | 0 | } |
133 | 0 | return Success; |
134 | 0 | } |
135 | | |
136 | | Result |
137 | | MapPRErrorCodeToResult(PRErrorCode error) |
138 | 0 | { |
139 | 0 | switch (error) |
140 | 0 | { |
141 | 0 | #define MOZILLA_PKIX_MAP(mozilla_pkix_result, value, nss_result) \ |
142 | 0 | case nss_result: return Result::mozilla_pkix_result; |
143 | 0 |
|
144 | 0 | MOZILLA_PKIX_MAP_LIST |
145 | 0 |
|
146 | 0 | #undef MOZILLA_PKIX_MAP |
147 | 0 |
|
148 | 0 | default: |
149 | 0 | return Result::ERROR_UNKNOWN_ERROR; |
150 | 0 | } |
151 | 0 | } |
152 | | |
153 | | PRErrorCode |
154 | | MapResultToPRErrorCode(Result result) |
155 | 0 | { |
156 | 0 | switch (result) |
157 | 0 | { |
158 | 0 | #define MOZILLA_PKIX_MAP(mozilla_pkix_result, value, nss_result) \ |
159 | 0 | case Result::mozilla_pkix_result: return nss_result; |
160 | 0 |
|
161 | 0 | MOZILLA_PKIX_MAP_LIST |
162 | 0 |
|
163 | 0 | #undef MOZILLA_PKIX_MAP |
164 | 0 |
|
165 | 0 | MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM |
166 | 0 | } |
167 | 0 | } |
168 | | |
169 | | void |
170 | | RegisterErrorTable() |
171 | 0 | { |
172 | 0 | // Note that these error strings are not localizable. |
173 | 0 | // When these strings change, update the localization information too. |
174 | 0 | static const PRErrorMessage ErrorTableText[] = { |
175 | 0 | { "MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE", |
176 | 0 | "The server uses key pinning (HPKP) but no trusted certificate chain " |
177 | 0 | "could be constructed that matches the pinset. Key pinning violations " |
178 | 0 | "cannot be overridden." }, |
179 | 0 | { "MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY", |
180 | 0 | "The server uses a certificate with a basic constraints extension " |
181 | 0 | "identifying it as a certificate authority. For a properly-issued " |
182 | 0 | "certificate, this should not be the case." }, |
183 | 0 | { "MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE", |
184 | 0 | "The server presented a certificate with a key size that is too small " |
185 | 0 | "to establish a secure connection." }, |
186 | 0 | { "MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA", |
187 | 0 | "An X.509 version 1 certificate that is not a trust anchor was used to " |
188 | 0 | "issue the server's certificate. X.509 version 1 certificates are " |
189 | 0 | "deprecated and should not be used to sign other certificates." }, |
190 | 0 | { "MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH", |
191 | 0 | "The certificate is not valid for the given email address." }, |
192 | 0 | { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE", |
193 | 0 | "The server presented a certificate that is not yet valid." }, |
194 | 0 | { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE", |
195 | 0 | "A certificate that is not yet valid was used to issue the server's " |
196 | 0 | "certificate." }, |
197 | 0 | { "MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH", |
198 | 0 | "The signature algorithm in the signature field of the certificate does " |
199 | 0 | "not match the algorithm in its signatureAlgorithm field." }, |
200 | 0 | { "MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING", |
201 | 0 | "The OCSP response does not include a status for the certificate being " |
202 | 0 | "verified." }, |
203 | 0 | { "MOZILLA_PKIX_ERROR_VALIDITY_TOO_LONG", |
204 | 0 | "The server presented a certificate that is valid for too long." }, |
205 | 0 | { "MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING", |
206 | 0 | "A required TLS feature is missing." }, |
207 | 0 | { "MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING", |
208 | 0 | "The server presented a certificate that contains an invalid encoding of " |
209 | 0 | "an integer. Common causes include negative serial numbers, negative RSA " |
210 | 0 | "moduli, and encodings that are longer than necessary." }, |
211 | 0 | { "MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME", |
212 | 0 | "The server presented a certificate with an empty issuer distinguished " |
213 | 0 | "name." }, |
214 | 0 | { "MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED", |
215 | 0 | "An additional policy constraint failed when validating this " |
216 | 0 | "certificate." }, |
217 | 0 | { "MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT", |
218 | 0 | "The certificate is not trusted because it is self-signed." }, |
219 | 0 | { "MOZILLA_PKIX_ERROR_MITM_DETECTED", |
220 | 0 | "Your connection is being intercepted by a TLS proxy. Uninstall it if " |
221 | 0 | "possible or configure your device to trust its root certificate." }, |
222 | 0 | }; |
223 | 0 | // Note that these error strings are not localizable. |
224 | 0 | // When these strings change, update the localization information too. |
225 | 0 |
|
226 | 0 | static const PRErrorTable ErrorTable = { |
227 | 0 | ErrorTableText, |
228 | 0 | "pkixerrors", |
229 | 0 | ERROR_BASE, |
230 | 0 | PR_ARRAY_SIZE(ErrorTableText) |
231 | 0 | }; |
232 | 0 |
|
233 | 0 | (void) PR_ErrorInstallTable(&ErrorTable); |
234 | 0 | } |
235 | | |
236 | | } } // namespace mozilla::pkix |