Line data Source code
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 0 : VerifySignedDigest(const SignedDigest& sd,
44 : Input subjectPublicKeyInfo,
45 : SECOidTag pubKeyAlg,
46 : void* pkcs11PinArg)
47 : {
48 : 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 : }
56 :
57 : SECItem subjectPublicKeyInfoSECItem =
58 0 : UnsafeMapInputToSECItem(subjectPublicKeyInfo);
59 : ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
60 0 : spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem));
61 0 : if (!spki) {
62 0 : return MapPRErrorCodeToResult(PR_GetError());
63 : }
64 : ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey>
65 0 : pubKey(SECKEY_ExtractPublicKey(spki.get()));
66 0 : if (!pubKey) {
67 0 : return MapPRErrorCodeToResult(PR_GetError());
68 : }
69 :
70 0 : SECItem digestSECItem(UnsafeMapInputToSECItem(sd.digest));
71 0 : SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature));
72 0 : SECStatus srv = VFY_VerifyDigestDirect(&digestSECItem, pubKey.get(),
73 : &signatureSECItem, pubKeyAlg,
74 0 : digestAlg, pkcs11PinArg);
75 0 : if (srv != SECSuccess) {
76 0 : return MapPRErrorCodeToResult(PR_GetError());
77 : }
78 :
79 0 : return Success;
80 : }
81 :
82 : } // namespace
83 :
84 : Result
85 0 : VerifyRSAPKCS1SignedDigestNSS(const SignedDigest& sd,
86 : Input subjectPublicKeyInfo,
87 : void* pkcs11PinArg)
88 : {
89 : return VerifySignedDigest(sd, subjectPublicKeyInfo,
90 0 : SEC_OID_PKCS1_RSA_ENCRYPTION, pkcs11PinArg);
91 : }
92 :
93 : Result
94 0 : VerifyECDSASignedDigestNSS(const SignedDigest& sd,
95 : Input subjectPublicKeyInfo,
96 : void* pkcs11PinArg)
97 : {
98 : return VerifySignedDigest(sd, subjectPublicKeyInfo,
99 0 : SEC_OID_ANSIX962_EC_PUBLIC_KEY, pkcs11PinArg);
100 : }
101 :
102 : Result
103 15 : DigestBufNSS(Input item,
104 : DigestAlgorithm digestAlg,
105 : /*out*/ uint8_t* digestBuf,
106 : size_t digestBufLen)
107 : {
108 : SECOidTag oid;
109 : size_t bits;
110 15 : 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 15 : 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 : }
117 15 : if (digestBufLen != bits / 8) {
118 0 : return Result::FATAL_ERROR_INVALID_ARGS;
119 : }
120 :
121 15 : SECItem itemSECItem = UnsafeMapInputToSECItem(item);
122 30 : if (itemSECItem.len >
123 15 : static_cast<decltype(itemSECItem.len)>(
124 15 : 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 : }
128 15 : SECStatus srv = PK11_HashBuf(oid, digestBuf, itemSECItem.data,
129 30 : static_cast<int32_t>(itemSECItem.len));
130 15 : if (srv != SECSuccess) {
131 0 : return MapPRErrorCodeToResult(PR_GetError());
132 : }
133 15 : return Success;
134 : }
135 :
136 : Result
137 0 : MapPRErrorCodeToResult(PRErrorCode error)
138 : {
139 0 : switch (error)
140 : {
141 : #define MOZILLA_PKIX_MAP(mozilla_pkix_result, value, nss_result) \
142 : case nss_result: return Result::mozilla_pkix_result;
143 :
144 0 : MOZILLA_PKIX_MAP_LIST
145 :
146 : #undef MOZILLA_PKIX_MAP
147 :
148 : default:
149 0 : return Result::ERROR_UNKNOWN_ERROR;
150 : }
151 : }
152 :
153 : PRErrorCode
154 0 : MapResultToPRErrorCode(Result result)
155 : {
156 0 : switch (result)
157 : {
158 : #define MOZILLA_PKIX_MAP(mozilla_pkix_result, value, nss_result) \
159 : case Result::mozilla_pkix_result: return nss_result;
160 :
161 0 : MOZILLA_PKIX_MAP_LIST
162 :
163 : #undef MOZILLA_PKIX_MAP
164 :
165 0 : MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
166 : }
167 : }
168 :
169 : void
170 1 : RegisterErrorTable()
171 : {
172 : // Note that these error strings are not localizable.
173 : // When these strings change, update the localization information too.
174 : static const PRErrorMessage ErrorTableText[] = {
175 : { "MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE",
176 : "The server uses key pinning (HPKP) but no trusted certificate chain "
177 : "could be constructed that matches the pinset. Key pinning violations "
178 : "cannot be overridden." },
179 : { "MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY",
180 : "The server uses a certificate with a basic constraints extension "
181 : "identifying it as a certificate authority. For a properly-issued "
182 : "certificate, this should not be the case." },
183 : { "MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE",
184 : "The server presented a certificate with a key size that is too small "
185 : "to establish a secure connection." },
186 : { "MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA",
187 : "An X.509 version 1 certificate that is not a trust anchor was used to "
188 : "issue the server's certificate. X.509 version 1 certificates are "
189 : "deprecated and should not be used to sign other certificates." },
190 : { "MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH",
191 : "The certificate is not valid for the given email address." },
192 : { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE",
193 : "The server presented a certificate that is not yet valid." },
194 : { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE",
195 : "A certificate that is not yet valid was used to issue the server's "
196 : "certificate." },
197 : { "MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH",
198 : "The signature algorithm in the signature field of the certificate does "
199 : "not match the algorithm in its signatureAlgorithm field." },
200 : { "MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING",
201 : "The OCSP response does not include a status for the certificate being "
202 : "verified." },
203 : { "MOZILLA_PKIX_ERROR_VALIDITY_TOO_LONG",
204 : "The server presented a certificate that is valid for too long." },
205 : { "MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING",
206 : "A required TLS feature is missing." },
207 : { "MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING",
208 : "The server presented a certificate that contains an invalid encoding of "
209 : "an integer. Common causes include negative serial numbers, negative RSA "
210 : "moduli, and encodings that are longer than necessary." },
211 : { "MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME",
212 : "The server presented a certificate with an empty issuer distinguished "
213 : "name." },
214 : };
215 : // Note that these error strings are not localizable.
216 : // When these strings change, update the localization information too.
217 :
218 : static const PRErrorTable ErrorTable = {
219 : ErrorTableText,
220 : "pkixerrors",
221 : ERROR_BASE,
222 : PR_ARRAY_SIZE(ErrorTableText)
223 : };
224 :
225 1 : (void) PR_ErrorInstallTable(&ErrorTable);
226 1 : }
227 :
228 : } } // namespace mozilla::pkix
|