|
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 #ifndef mozilla_pkix__pkixutil_h |
|
19 #define mozilla_pkix__pkixutil_h |
|
20 |
|
21 #include "pkix/pkixtypes.h" |
|
22 #include "prerror.h" |
|
23 #include "seccomon.h" |
|
24 #include "secerr.h" |
|
25 |
|
26 namespace mozilla { namespace pkix { |
|
27 |
|
28 enum Result |
|
29 { |
|
30 Success = 0, |
|
31 FatalError = -1, // An error was encountered that caused path building |
|
32 // to stop immediately. example: out-of-memory. |
|
33 RecoverableError = -2 // an error that will cause path building to continue |
|
34 // searching for alternative paths. example: expired |
|
35 // certificate. |
|
36 }; |
|
37 |
|
38 // When returning errors, use this function instead of calling PR_SetError |
|
39 // directly. This helps ensure that we always call PR_SetError when we return |
|
40 // an error code. This is a useful place to set a breakpoint when a debugging |
|
41 // a certificate verification failure. |
|
42 inline Result |
|
43 Fail(Result result, PRErrorCode errorCode) |
|
44 { |
|
45 PR_ASSERT(result != Success); |
|
46 PR_SetError(errorCode, 0); |
|
47 return result; |
|
48 } |
|
49 |
|
50 inline Result |
|
51 MapSECStatus(SECStatus srv) |
|
52 { |
|
53 if (srv == SECSuccess) { |
|
54 return Success; |
|
55 } |
|
56 |
|
57 PRErrorCode error = PORT_GetError(); |
|
58 switch (error) { |
|
59 case SEC_ERROR_EXTENSION_NOT_FOUND: |
|
60 return RecoverableError; |
|
61 |
|
62 case PR_INVALID_STATE_ERROR: |
|
63 case SEC_ERROR_LIBRARY_FAILURE: |
|
64 case SEC_ERROR_NO_MEMORY: |
|
65 return FatalError; |
|
66 } |
|
67 |
|
68 // TODO: PORT_Assert(false); // we haven't classified the error yet |
|
69 return RecoverableError; |
|
70 } |
|
71 |
|
72 // During path building and verification, we build a linked list of BackCerts |
|
73 // from the current cert toward the end-entity certificate. The linked list |
|
74 // is used to verify properties that aren't local to the current certificate |
|
75 // and/or the direct link between the current certificate and its issuer, |
|
76 // such as name constraints. |
|
77 // |
|
78 // Each BackCert contains pointers to all the given certificate's extensions |
|
79 // so that we can parse the extension block once and then process the |
|
80 // extensions in an order that may be different than they appear in the cert. |
|
81 class BackCert |
|
82 { |
|
83 public: |
|
84 // ExcludeCN means that GetConstrainedNames won't include the subject CN in |
|
85 // its results. IncludeCN means that GetConstrainedNames will include the |
|
86 // subject CN in its results. |
|
87 enum ConstrainedNameOptions { ExcludeCN = 0, IncludeCN = 1 }; |
|
88 |
|
89 // nssCert and childCert must be valid for the lifetime of BackCert |
|
90 BackCert(CERTCertificate* nssCert, BackCert* childCert, |
|
91 ConstrainedNameOptions cnOptions) |
|
92 : encodedBasicConstraints(nullptr) |
|
93 , encodedCertificatePolicies(nullptr) |
|
94 , encodedExtendedKeyUsage(nullptr) |
|
95 , encodedKeyUsage(nullptr) |
|
96 , encodedNameConstraints(nullptr) |
|
97 , encodedInhibitAnyPolicy(nullptr) |
|
98 , childCert(childCert) |
|
99 , nssCert(nssCert) |
|
100 , constrainedNames(nullptr) |
|
101 , cnOptions(cnOptions) |
|
102 { |
|
103 } |
|
104 |
|
105 Result Init(); |
|
106 |
|
107 const SECItem* encodedBasicConstraints; |
|
108 const SECItem* encodedCertificatePolicies; |
|
109 const SECItem* encodedExtendedKeyUsage; |
|
110 const SECItem* encodedKeyUsage; |
|
111 const SECItem* encodedNameConstraints; |
|
112 const SECItem* encodedInhibitAnyPolicy; |
|
113 |
|
114 BackCert* const childCert; |
|
115 |
|
116 // Only non-const so that we can pass this to TrustDomain::IsRevoked, |
|
117 // which only takes a non-const pointer because VerifyEncodedOCSPResponse |
|
118 // requires it, and that is only because the implementation of |
|
119 // VerifyEncodedOCSPResponse does a CERT_DupCertificate. TODO: get rid |
|
120 // of that CERT_DupCertificate so that we can make all these things const. |
|
121 /*const*/ CERTCertificate* GetNSSCert() const { return nssCert; } |
|
122 |
|
123 // Returns the names that should be considered when evaluating name |
|
124 // constraints. The list is constructed lazily and cached. The result is a |
|
125 // weak reference; do not try to free it, and do not hold long-lived |
|
126 // references to it. |
|
127 Result GetConstrainedNames(/*out*/ const CERTGeneralName** result); |
|
128 |
|
129 // This is the only place where we should be dealing with non-const |
|
130 // CERTCertificates. |
|
131 Result PrependNSSCertToList(CERTCertList* results); |
|
132 |
|
133 PLArenaPool* GetArena(); |
|
134 |
|
135 private: |
|
136 CERTCertificate* nssCert; |
|
137 |
|
138 ScopedPLArenaPool arena; |
|
139 CERTGeneralName* constrainedNames; |
|
140 ConstrainedNameOptions cnOptions; |
|
141 |
|
142 BackCert(const BackCert&) /* = delete */; |
|
143 void operator=(const BackCert&); /* = delete */; |
|
144 }; |
|
145 |
|
146 } } // namespace mozilla::pkix |
|
147 |
|
148 #endif // mozilla_pkix__pkixutil_h |