Coverage Report

Created: 2018-09-25 14:53

/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