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_pl_ocsprequest.c
6  *
7  */
8 
9 #include "pkix_pl_ocsprequest.h"
10 
11 /* --Private-OcspRequest-Functions------------------------------------- */
12 
13 /*
14  * FUNCTION: pkix_pl_OcspRequest_Destroy
15  * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
16  */
17 static PKIX_Error *
pkix_pl_OcspRequest_Destroy(PKIX_PL_Object * object,void * plContext)18 pkix_pl_OcspRequest_Destroy(
19         PKIX_PL_Object *object,
20         void *plContext)
21 {
22         PKIX_PL_OcspRequest *ocspReq = NULL;
23 
24         PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Destroy");
25         PKIX_NULLCHECK_ONE(object);
26 
27         PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext),
28                     PKIX_OBJECTNOTOCSPREQUEST);
29 
30         ocspReq = (PKIX_PL_OcspRequest *)object;
31 
32         if (ocspReq->decoded != NULL) {
33                 CERT_DestroyOCSPRequest(ocspReq->decoded);
34         }
35 
36         if (ocspReq->encoded != NULL) {
37                 SECITEM_FreeItem(ocspReq->encoded, PR_TRUE);
38         }
39 
40         if (ocspReq->location != NULL) {
41                 PORT_Free(ocspReq->location);
42         }
43 
44         PKIX_DECREF(ocspReq->cert);
45         PKIX_DECREF(ocspReq->validity);
46         PKIX_DECREF(ocspReq->signerCert);
47 
48 cleanup:
49 
50         PKIX_RETURN(OCSPREQUEST);
51 }
52 
53 /*
54  * FUNCTION: pkix_pl_OcspRequest_Hashcode
55  * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
56  */
57 static PKIX_Error *
pkix_pl_OcspRequest_Hashcode(PKIX_PL_Object * object,PKIX_UInt32 * pHashcode,void * plContext)58 pkix_pl_OcspRequest_Hashcode(
59         PKIX_PL_Object *object,
60         PKIX_UInt32 *pHashcode,
61         void *plContext)
62 {
63         PKIX_UInt32 certHash = 0;
64         PKIX_UInt32 dateHash = 0;
65         PKIX_UInt32 extensionHash = 0;
66         PKIX_UInt32 signerHash = 0;
67         PKIX_PL_OcspRequest *ocspRq = NULL;
68 
69         PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Hashcode");
70         PKIX_NULLCHECK_TWO(object, pHashcode);
71 
72         PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext),
73                     PKIX_OBJECTNOTOCSPREQUEST);
74 
75         ocspRq = (PKIX_PL_OcspRequest *)object;
76 
77         *pHashcode = 0;
78 
79         PKIX_HASHCODE(ocspRq->cert, &certHash, plContext,
80                 PKIX_CERTHASHCODEFAILED);
81 
82         PKIX_HASHCODE(ocspRq->validity, &dateHash, plContext,
83                 PKIX_DATEHASHCODEFAILED);
84 
85         if (ocspRq->addServiceLocator == PKIX_TRUE) {
86                 extensionHash = 0xff;
87         }
88 
89         PKIX_HASHCODE(ocspRq->signerCert, &signerHash, plContext,
90                 PKIX_CERTHASHCODEFAILED);
91 
92         *pHashcode = (((((extensionHash << 8) | certHash) << 8) |
93                 dateHash) << 8) | signerHash;
94 
95 cleanup:
96 
97         PKIX_RETURN(OCSPREQUEST);
98 
99 }
100 
101 /*
102  * FUNCTION: pkix_pl_OcspRequest_Equals
103  * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
104  */
105 static PKIX_Error *
pkix_pl_OcspRequest_Equals(PKIX_PL_Object * firstObj,PKIX_PL_Object * secondObj,PKIX_Boolean * pResult,void * plContext)106 pkix_pl_OcspRequest_Equals(
107         PKIX_PL_Object *firstObj,
108         PKIX_PL_Object *secondObj,
109         PKIX_Boolean *pResult,
110         void *plContext)
111 {
112         PKIX_Boolean match = PKIX_FALSE;
113         PKIX_UInt32 secondType = 0;
114         PKIX_PL_OcspRequest *firstReq = NULL;
115         PKIX_PL_OcspRequest *secondReq = NULL;
116 
117         PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Equals");
118         PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
119 
120         /* test that firstObj is a OcspRequest */
121         PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPREQUEST_TYPE, plContext),
122                     PKIX_FIRSTOBJARGUMENTNOTOCSPREQUEST);
123 
124         /*
125          * Since we know firstObj is a OcspRequest, if both references are
126          * identical, they must be equal
127          */
128         if (firstObj == secondObj){
129                 match = PKIX_TRUE;
130                 goto cleanup;
131         }
132 
133         /*
134          * If secondObj isn't a OcspRequest, we don't throw an error.
135          * We simply return a Boolean result of FALSE
136          */
137         PKIX_CHECK(PKIX_PL_Object_GetType
138                     (secondObj, &secondType, plContext),
139                     PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
140         if (secondType != PKIX_OCSPREQUEST_TYPE) {
141                 goto cleanup;
142         }
143 
144         firstReq = (PKIX_PL_OcspRequest *)firstObj;
145         secondReq = (PKIX_PL_OcspRequest *)secondObj;
146 
147         if (firstReq->addServiceLocator != secondReq->addServiceLocator) {
148                 goto cleanup;
149         }
150 
151         PKIX_EQUALS(firstReq->cert, secondReq->cert, &match, plContext,
152                 PKIX_CERTEQUALSFAILED);
153 
154         if (match == PKIX_FALSE) {
155                 goto cleanup;
156         }
157 
158         PKIX_EQUALS(firstReq->validity, secondReq->validity, &match, plContext,
159                 PKIX_DATEEQUALSFAILED);
160 
161         if (match == PKIX_FALSE) {
162                 goto cleanup;
163         }
164 
165         PKIX_EQUALS
166                 (firstReq->signerCert, secondReq->signerCert, &match, plContext,
167                 PKIX_CERTEQUALSFAILED);
168 
169 cleanup:
170 
171         *pResult = match;
172 
173         PKIX_RETURN(OCSPREQUEST);
174 }
175 
176 /*
177  * FUNCTION: pkix_pl_OcspRequest_RegisterSelf
178  * DESCRIPTION:
179  *  Registers PKIX_OCSPREQUEST_TYPE and its related functions with
180  *  systemClasses[]
181  * PARAMETERS:
182  *  "plContext"
183  *      Platform-specific context pointer.
184  * THREAD SAFETY:
185  *  Not Thread Safe - for performance and complexity reasons
186  *
187  *  Since this function is only called by PKIX_PL_Initialize, which should
188  *  only be called once, it is acceptable that this function is not
189  *  thread-safe.
190  */
191 PKIX_Error *
pkix_pl_OcspRequest_RegisterSelf(void * plContext)192 pkix_pl_OcspRequest_RegisterSelf(void *plContext)
193 {
194         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
195         pkix_ClassTable_Entry entry;
196 
197         PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_RegisterSelf");
198 
199         entry.description = "OcspRequest";
200         entry.objCounter = 0;
201         entry.typeObjectSize = sizeof(PKIX_PL_OcspRequest);
202         entry.destructor = pkix_pl_OcspRequest_Destroy;
203         entry.equalsFunction = pkix_pl_OcspRequest_Equals;
204         entry.hashcodeFunction = pkix_pl_OcspRequest_Hashcode;
205         entry.toStringFunction = NULL;
206         entry.comparator = NULL;
207         entry.duplicateFunction = pkix_duplicateImmutable;
208 
209         systemClasses[PKIX_OCSPREQUEST_TYPE] = entry;
210 
211         PKIX_RETURN(OCSPREQUEST);
212 }
213 
214 /* --Public-Functions------------------------------------------------------- */
215 
216 /*
217  * FUNCTION: pkix_pl_OcspRequest_Create
218  * DESCRIPTION:
219  *
220  *  This function creates an OcspRequest to be used in validating the Cert
221  *  pointed to by "cert" and storing the result at "pRequest". If a URI
222  *  is found for an OCSP responder, PKIX_TRUE is stored at "pURIFound". If no
223  *  URI is found, PKIX_FALSE is stored.
224  *
225  *  If a Date is provided in "validity" it may be used in the search for the
226  *  issuer of "cert" but has no effect on the request itself. If
227  *  "addServiceLocator" is TRUE, the AddServiceLocator extension will be
228  *  included in the Request. If "signerCert" is provided it will be used to sign
229  *  the Request. (Note: this signed request feature is not currently supported.)
230  *
231  * PARAMETERS:
232  *  "cert"
233  *     Address of the Cert for which an OcspRequest is to be created. Must be
234  *     non-NULL.
235  *  "validity"
236  *     Address of the Date for which the Cert's validity is to be determined.
237  *     May be NULL.
238  *  "signerCert"
239  *     Address of the Cert to be used, if present, in signing the request.
240  *     May be NULL.
241  *  "pRequest"
242  *     Address at which the result is stored. Must be non-NULL.
243  *  "plContext"
244  *      Platform-specific context pointer.
245  * THREAD SAFETY:
246  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
247  * RETURNS:
248  *  Returns NULL if the function succeeds.
249  *  Returns an OcspRequest Error if the function fails in a non-fatal way.
250  *  Returns a Fatal Error if the function fails in an unrecoverable way.
251  */
252 PKIX_Error *
pkix_pl_OcspRequest_Create(PKIX_PL_Cert * cert,PKIX_PL_OcspCertID * cid,PKIX_PL_Date * validity,PKIX_PL_Cert * signerCert,PKIX_UInt32 methodFlags,PKIX_Boolean * pURIFound,PKIX_PL_OcspRequest ** pRequest,void * plContext)253 pkix_pl_OcspRequest_Create(
254         PKIX_PL_Cert *cert,
255         PKIX_PL_OcspCertID *cid,
256         PKIX_PL_Date *validity,
257         PKIX_PL_Cert *signerCert,
258         PKIX_UInt32 methodFlags,
259         PKIX_Boolean *pURIFound,
260         PKIX_PL_OcspRequest **pRequest,
261         void *plContext)
262 {
263         PKIX_PL_OcspRequest *ocspRequest = NULL;
264 
265         CERTCertDBHandle *handle = NULL;
266         SECStatus rv = SECFailure;
267         SECItem *encoding = NULL;
268         CERTOCSPRequest *certRequest = NULL;
269         PRTime time = 0;
270         PRBool addServiceLocatorExtension = PR_FALSE;
271         CERTCertificate *nssCert = NULL;
272         CERTCertificate *nssSignerCert = NULL;
273         char *location = NULL;
274         PRErrorCode locError = 0;
275         PKIX_Boolean canUseDefaultSource = PKIX_FALSE;
276 
277         PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Create");
278         PKIX_NULLCHECK_TWO(cert, pRequest);
279 
280         /* create a PKIX_PL_OcspRequest object */
281         PKIX_CHECK(PKIX_PL_Object_Alloc
282                     (PKIX_OCSPREQUEST_TYPE,
283                     sizeof (PKIX_PL_OcspRequest),
284                     (PKIX_PL_Object **)&ocspRequest,
285                     plContext),
286                     PKIX_COULDNOTCREATEOBJECT);
287 
288         PKIX_INCREF(cert);
289         ocspRequest->cert = cert;
290 
291         PKIX_INCREF(validity);
292         ocspRequest->validity = validity;
293 
294         PKIX_INCREF(signerCert);
295         ocspRequest->signerCert = signerCert;
296 
297         ocspRequest->decoded = NULL;
298         ocspRequest->encoded = NULL;
299 
300         ocspRequest->location = NULL;
301 
302         nssCert = cert->nssCert;
303 
304         /*
305          * Does this Cert have an Authority Information Access extension with
306          * the URI of an OCSP responder?
307          */
308         handle = CERT_GetDefaultCertDB();
309 
310         if (!(methodFlags & PKIX_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE)) {
311             canUseDefaultSource = PKIX_TRUE;
312         }
313         location = ocsp_GetResponderLocation(handle, nssCert,
314                                              canUseDefaultSource,
315                                              &addServiceLocatorExtension);
316         if (location == NULL) {
317                 locError = PORT_GetError();
318                 if (locError == SEC_ERROR_EXTENSION_NOT_FOUND ||
319                     locError == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) {
320                     PORT_SetError(0);
321                     *pURIFound = PKIX_FALSE;
322                     goto cleanup;
323                 }
324                 PKIX_ERROR(PKIX_ERRORFINDINGORPROCESSINGURI);
325         }
326 
327         ocspRequest->location = location;
328         *pURIFound = PKIX_TRUE;
329 
330         if (signerCert != NULL) {
331                 nssSignerCert = signerCert->nssCert;
332         }
333 
334         if (validity != NULL) {
335 		PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext),
336 			PKIX_DATEGETPRTIMEFAILED);
337         } else {
338                 time = PR_Now();
339 	}
340 
341         certRequest = cert_CreateSingleCertOCSPRequest(
342                 cid->certID, cert->nssCert, time,
343                 addServiceLocatorExtension, nssSignerCert);
344 
345         ocspRequest->decoded = certRequest;
346 
347         if (certRequest == NULL) {
348                 PKIX_ERROR(PKIX_UNABLETOCREATECERTOCSPREQUEST);
349         }
350 
351         rv = CERT_AddOCSPAcceptableResponses(
352                 certRequest, SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
353 
354         if (rv == SECFailure) {
355                 PKIX_ERROR(PKIX_UNABLETOADDACCEPTABLERESPONSESTOREQUEST);
356         }
357 
358         encoding = CERT_EncodeOCSPRequest(NULL, certRequest, NULL);
359 
360         ocspRequest->encoded = encoding;
361 
362         *pRequest = ocspRequest;
363         ocspRequest = NULL;
364 
365 cleanup:
366         PKIX_DECREF(ocspRequest);
367 
368         PKIX_RETURN(OCSPREQUEST);
369 }
370 
371 /*
372  * FUNCTION: pkix_pl_OcspRequest_GetEncoded
373  * DESCRIPTION:
374  *
375  *  This function obtains the encoded message from the OcspRequest pointed to
376  *  by "request", storing the result at "pRequest".
377  *
378  * PARAMETERS
379  *  "request"
380  *      The address of the OcspRequest whose encoded message is to be
381  *      retrieved. Must be non-NULL.
382  *  "pRequest"
383  *      The address at which is stored the address of the encoded message. Must
384  *      be non-NULL.
385  *  "plContext"
386  *      Platform-specific context pointer.
387  * THREAD SAFETY:
388  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
389  * RETURNS:
390  *  Returns NULL if the function succeeds.
391  *  Returns a Fatal Error if the function fails in an unrecoverable way.
392  */
393 PKIX_Error *
pkix_pl_OcspRequest_GetEncoded(PKIX_PL_OcspRequest * request,SECItem ** pRequest,void * plContext)394 pkix_pl_OcspRequest_GetEncoded(
395         PKIX_PL_OcspRequest *request,
396         SECItem **pRequest,
397         void *plContext)
398 {
399         PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetEncoded");
400         PKIX_NULLCHECK_TWO(request, pRequest);
401 
402         *pRequest = request->encoded;
403 
404         PKIX_RETURN(OCSPREQUEST);
405 }
406 
407 /*
408  * FUNCTION: pkix_pl_OcspRequest_GetLocation
409  * DESCRIPTION:
410  *
411  *  This function obtains the location from the OcspRequest pointed to
412  *  by "request", storing the result at "pLocation".
413  *
414  * PARAMETERS
415  *  "request"
416  *      The address of the OcspRequest whose encoded message is to be
417  *      retrieved. Must be non-NULL.
418  *  "pLocation"
419  *      The address at which is stored the address of the location. Must
420  *      be non-NULL.
421  *  "plContext"
422  *      Platform-specific context pointer.
423  * THREAD SAFETY:
424  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
425  * RETURNS:
426  *  Returns NULL if the function succeeds.
427  *  Returns a Fatal Error if the function fails in an unrecoverable way.
428  */
429 PKIX_Error *
pkix_pl_OcspRequest_GetLocation(PKIX_PL_OcspRequest * request,char ** pLocation,void * plContext)430 pkix_pl_OcspRequest_GetLocation(
431         PKIX_PL_OcspRequest *request,
432         char **pLocation,
433         void *plContext)
434 {
435         PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetLocation");
436         PKIX_NULLCHECK_TWO(request, pLocation);
437 
438         *pLocation = request->location;
439 
440         PKIX_RETURN(OCSPREQUEST);
441 }
442