1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /*
5  * pkix_ekuchecker.c
6  *
7  * User Defined ExtenedKeyUsage Function Definitions
8  *
9  */
10 
11 #include "pkix_ekuchecker.h"
12 
13 SECOidTag ekuOidStrings[] = {
14     PKIX_KEY_USAGE_SERVER_AUTH_OID,
15     PKIX_KEY_USAGE_CLIENT_AUTH_OID,
16     PKIX_KEY_USAGE_CODE_SIGN_OID,
17     PKIX_KEY_USAGE_EMAIL_PROTECT_OID,
18     PKIX_KEY_USAGE_TIME_STAMP_OID,
19     PKIX_KEY_USAGE_OCSP_RESPONDER_OID,
20     PKIX_UNKNOWN_OID
21 };
22 
23 typedef struct pkix_EkuCheckerStruct {
24     PKIX_List *requiredExtKeyUsageOids;
25     PKIX_PL_OID *ekuOID;
26 } pkix_EkuChecker;
27 
28 
29 /*
30  * FUNCTION: pkix_EkuChecker_Destroy
31  * (see comments for PKIX_DestructorCallback in pkix_pl_system.h)
32  */
33 static PKIX_Error *
pkix_EkuChecker_Destroy(PKIX_PL_Object * object,void * plContext)34 pkix_EkuChecker_Destroy(
35         PKIX_PL_Object *object,
36         void *plContext)
37 {
38         pkix_EkuChecker *ekuCheckerState = NULL;
39 
40         PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Destroy");
41         PKIX_NULLCHECK_ONE(object);
42 
43         PKIX_CHECK(pkix_CheckType(object, PKIX_EKUCHECKER_TYPE, plContext),
44                     PKIX_OBJECTNOTANEKUCHECKERSTATE);
45 
46         ekuCheckerState = (pkix_EkuChecker *)object;
47 
48         PKIX_DECREF(ekuCheckerState->ekuOID);
49         PKIX_DECREF(ekuCheckerState->requiredExtKeyUsageOids);
50 
51 cleanup:
52 
53         PKIX_RETURN(EKUCHECKER);
54 }
55 
56 /*
57  * FUNCTION: pkix_EkuChecker_RegisterSelf
58  *
59  * DESCRIPTION:
60  *  Registers PKIX_PL_HTTPCERTSTORECONTEXT_TYPE and its related
61  *  functions with systemClasses[]
62  *
63  * THREAD SAFETY:
64  *  Not Thread Safe - for performance and complexity reasons
65  *
66  *  Since this function is only called by PKIX_PL_Initialize, which should
67  *  only be called once, it is acceptable that this function is not
68  *  thread-safe.
69  */
70 PKIX_Error *
pkix_EkuChecker_RegisterSelf(void * plContext)71 pkix_EkuChecker_RegisterSelf(void *plContext)
72 {
73         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
74         pkix_ClassTable_Entry *entry = &systemClasses[PKIX_EKUCHECKER_TYPE];
75 
76         PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_RegisterSelf");
77 
78         entry->description = "EkuChecker";
79         entry->typeObjectSize = sizeof(pkix_EkuChecker);
80         entry->destructor = pkix_EkuChecker_Destroy;
81 
82         PKIX_RETURN(EKUCHECKER);
83 }
84 
85 /*
86  * FUNCTION: pkix_EkuChecker_Create
87  * DESCRIPTION:
88  *
89  *  Creates a new Extend Key Usage CheckerState using "params" to retrieve
90  *  application specified EKU for verification and stores it at "pState".
91  *
92  * PARAMETERS:
93  *  "params"
94  *      a PKIX_ProcessingParams links to PKIX_ComCertSelParams where a list of
95  *      Extended Key Usage OIDs specified by application can be retrieved for
96  *      verification.
97  *  "pState"
98  *      Address where state pointer will be stored. Must be non-NULL.
99  *  "plContext"
100  *      Platform-specific context pointer.
101  * THREAD SAFETY:
102  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
103  * RETURNS:
104  *  Returns NULL if the function succeeds.
105  *  Returns a UserDefinedModules Error if the function fails in a
106  *      non-fatal way.
107  *  Returns a Fatal Error if the function fails in an unrecoverable way.
108  */
109 static PKIX_Error *
pkix_EkuChecker_Create(PKIX_ProcessingParams * params,pkix_EkuChecker ** pState,void * plContext)110 pkix_EkuChecker_Create(
111         PKIX_ProcessingParams *params,
112         pkix_EkuChecker **pState,
113         void *plContext)
114 {
115         pkix_EkuChecker *state = NULL;
116         PKIX_CertSelector *certSelector = NULL;
117         PKIX_ComCertSelParams *comCertSelParams = NULL;
118         PKIX_List *requiredOids = NULL;
119 
120         PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Create");
121         PKIX_NULLCHECK_TWO(params, pState);
122 
123         PKIX_CHECK(PKIX_PL_Object_Alloc
124                     (PKIX_EKUCHECKER_TYPE,
125                     sizeof (pkix_EkuChecker),
126                     (PKIX_PL_Object **)&state,
127                     plContext),
128                     PKIX_COULDNOTCREATEEKUCHECKERSTATEOBJECT);
129 
130 
131         PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints
132                     (params, &certSelector, plContext),
133                     PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED);
134 
135         if (certSelector != NULL) {
136 
137             /* Get initial EKU OIDs from ComCertSelParams, if set */
138             PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
139                        (certSelector, &comCertSelParams, plContext),
140                        PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED);
141 
142             if (comCertSelParams != NULL) {
143                 PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage
144                            (comCertSelParams, &requiredOids, plContext),
145                            PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED);
146 
147             }
148         }
149 
150         PKIX_CHECK(PKIX_PL_OID_Create
151                     (PKIX_EXTENDEDKEYUSAGE_OID,
152                     &state->ekuOID,
153                     plContext),
154                     PKIX_OIDCREATEFAILED);
155 
156         state->requiredExtKeyUsageOids = requiredOids;
157         requiredOids = NULL;
158         *pState = state;
159         state = NULL;
160 
161 cleanup:
162 
163         PKIX_DECREF(certSelector);
164         PKIX_DECREF(comCertSelParams);
165         PKIX_DECREF(requiredOids);
166         PKIX_DECREF(state);
167 
168         PKIX_RETURN(EKUCHECKER);
169 }
170 
171 /*
172  * FUNCTION: pkix_EkuChecker_Check
173  * DESCRIPTION:
174  *
175  *  This function determines the Extended Key Usage OIDs specified by the
176  *  application is included in the Extended Key Usage OIDs of this "cert".
177  *
178  * PARAMETERS:
179  *  "checker"
180  *      Address of CertChainChecker which has the state data.
181  *      Must be non-NULL.
182  *  "cert"
183  *      Address of Certificate that is to be validated. Must be non-NULL.
184  *  "unresolvedCriticalExtensions"
185  *      A List OIDs. The OID for Extended Key Usage is removed.
186  *  "plContext"
187  *      Platform-specific context pointer.
188  * THREAD SAFETY:
189  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
190  * RETURNS:
191  *  Returns NULL if the function succeeds.
192  *  Returns a UserDefinedModules Error if the function fails in
193  *      a non-fatal way.
194  *  Returns a Fatal Error if the function fails in an unrecoverable way.
195  */
196 static PKIX_Error *
pkix_EkuChecker_Check(PKIX_CertChainChecker * checker,PKIX_PL_Cert * cert,PKIX_List * unresolvedCriticalExtensions,void ** pNBIOContext,void * plContext)197 pkix_EkuChecker_Check(
198         PKIX_CertChainChecker *checker,
199         PKIX_PL_Cert *cert,
200         PKIX_List *unresolvedCriticalExtensions,
201         void **pNBIOContext,
202         void *plContext)
203 {
204         pkix_EkuChecker *state = NULL;
205         PKIX_List *requiredExtKeyUsageList = NULL;
206         PKIX_List *certExtKeyUsageList = NULL;
207         PKIX_PL_OID *ekuOid = NULL;
208         PKIX_Boolean isContained = PKIX_FALSE;
209         PKIX_UInt32 numItems = 0;
210         PKIX_UInt32 i;
211         PKIX_Boolean checkResult = PKIX_TRUE;
212 
213         PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Check");
214         PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext);
215 
216         *pNBIOContext = NULL; /* no non-blocking IO */
217 
218         PKIX_CHECK(
219             PKIX_CertChainChecker_GetCertChainCheckerState
220             (checker, (PKIX_PL_Object **)&state, plContext),
221             PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED);
222 
223         requiredExtKeyUsageList = state->requiredExtKeyUsageOids;
224         if (requiredExtKeyUsageList == NULL) {
225             goto cleanup;
226         }
227 
228         PKIX_CHECK(
229             PKIX_List_GetLength(requiredExtKeyUsageList, &numItems,
230                                 plContext),
231             PKIX_LISTGETLENGTHFAILED);
232         if (numItems == 0) {
233             goto cleanup;
234         }
235 
236         PKIX_CHECK(
237             PKIX_PL_Cert_GetExtendedKeyUsage(cert, &certExtKeyUsageList,
238                                              plContext),
239             PKIX_CERTGETEXTENDEDKEYUSAGEFAILED);
240 
241         if (certExtKeyUsageList == NULL) {
242             goto cleanup;
243         }
244 
245         for (i = 0; i < numItems; i++) {
246 
247             PKIX_CHECK(
248                 PKIX_List_GetItem(requiredExtKeyUsageList, i,
249                                   (PKIX_PL_Object **)&ekuOid, plContext),
250                 PKIX_LISTGETITEMFAILED);
251 
252             PKIX_CHECK(
253                 pkix_List_Contains(certExtKeyUsageList,
254                                    (PKIX_PL_Object *)ekuOid,
255                                    &isContained,
256                                    plContext),
257                 PKIX_LISTCONTAINSFAILED);
258 
259             PKIX_DECREF(ekuOid);
260             if (isContained != PKIX_TRUE) {
261                 checkResult = PKIX_FALSE;
262                 goto cleanup;
263             }
264         }
265 
266 cleanup:
267         if (!pkixErrorResult && checkResult == PKIX_FALSE) {
268             pkixErrorReceived = PKIX_TRUE;
269             pkixErrorCode = PKIX_EXTENDEDKEYUSAGECHECKINGFAILED;
270         }
271 
272         PKIX_DECREF(ekuOid);
273         PKIX_DECREF(certExtKeyUsageList);
274         PKIX_DECREF(state);
275 
276         PKIX_RETURN(EKUCHECKER);
277 }
278 
279 /*
280  * FUNCTION: pkix_EkuChecker_Initialize
281  * (see comments in pkix_sample_modules.h)
282  */
283 PKIX_Error *
PKIX_EkuChecker_Create(PKIX_ProcessingParams * params,PKIX_CertChainChecker ** pEkuChecker,void * plContext)284 PKIX_EkuChecker_Create(
285         PKIX_ProcessingParams *params,
286         PKIX_CertChainChecker **pEkuChecker,
287         void *plContext)
288 {
289         pkix_EkuChecker *state = NULL;
290         PKIX_List *critExtOIDsList = NULL;
291 
292         PKIX_ENTER(EKUCHECKER, "PKIX_EkuChecker_Initialize");
293         PKIX_NULLCHECK_ONE(params);
294 
295         /*
296          * This function and functions in this file provide an example of how
297          * an application defined checker can be hooked into libpkix.
298          */
299 
300         PKIX_CHECK(pkix_EkuChecker_Create
301                     (params, &state, plContext),
302                     PKIX_EKUCHECKERSTATECREATEFAILED);
303 
304         PKIX_CHECK(PKIX_List_Create(&critExtOIDsList, plContext),
305                     PKIX_LISTCREATEFAILED);
306 
307         PKIX_CHECK(PKIX_List_AppendItem
308                     (critExtOIDsList,
309                     (PKIX_PL_Object *)state->ekuOID,
310                     plContext),
311                     PKIX_LISTAPPENDITEMFAILED);
312 
313         PKIX_CHECK(PKIX_CertChainChecker_Create
314                 (pkix_EkuChecker_Check,
315                 PKIX_TRUE,                 /* forwardCheckingSupported */
316                 PKIX_FALSE,                /* forwardDirectionExpected */
317                 critExtOIDsList,
318                 (PKIX_PL_Object *) state,
319                 pEkuChecker,
320                 plContext),
321                 PKIX_CERTCHAINCHECKERCREATEFAILED);
322 cleanup:
323 
324         PKIX_DECREF(critExtOIDsList);
325         PKIX_DECREF(state);
326 
327         PKIX_RETURN(EKUCHECKER);
328 }
329