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_httpcertstore.c
6  *
7  * HTTPCertStore Function Definitions
8  *
9  */
10 
11 /* We can't decode the length of a message without at least this many bytes */
12 
13 #include "pkix_pl_httpcertstore.h"
14 extern PKIX_PL_HashTable *httpSocketCache;
15 SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate)
SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)16 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
17 SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate)
18 SEC_ASN1_MKSUB(CERT_SetOfSignedCrlTemplate)
19 
20 SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate)
21 SEC_ASN1_CHOOSER_DECLARE(SECOID_AlgorithmIDTemplate)
22 /* SEC_ASN1_CHOOSER_DECLARE(SEC_SetOfAnyTemplate)
23 SEC_ASN1_CHOOSER_DECLARE(CERT_SetOfSignedCrlTemplate)
24 
25 const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = {
26     { SEC_ASN1_SEQUENCE,
27 	  0, NULL, sizeof(CERTIssuerAndSN) },
28     { SEC_ASN1_SAVE,
29 	  offsetof(CERTIssuerAndSN,derIssuer) },
30     { SEC_ASN1_INLINE,
31 	  offsetof(CERTIssuerAndSN,issuer),
32 	  CERT_NameTemplate },
33     { SEC_ASN1_INTEGER,
34 	  offsetof(CERTIssuerAndSN,serialNumber) },
35     { 0 }
36 };
37 
38 const SEC_ASN1Template SECOID_AlgorithmIDTemplate[] = {
39     { SEC_ASN1_SEQUENCE,
40 	  0, NULL, sizeof(SECAlgorithmID) },
41     { SEC_ASN1_OBJECT_ID,
42 	  offsetof(SECAlgorithmID,algorithm) },
43     { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
44 	  offsetof(SECAlgorithmID,parameters) },
45     { 0 }
46 }; */
47 
48 /* --Private-HttpCertStoreContext-Object Functions----------------------- */
49 
50 /*
51  * FUNCTION: pkix_pl_HttpCertStoreContext_Destroy
52  * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
53  */
54 static PKIX_Error *
55 pkix_pl_HttpCertStoreContext_Destroy(
56         PKIX_PL_Object *object,
57         void *plContext)
58 {
59         const SEC_HttpClientFcnV1 *hcv1 = NULL;
60         PKIX_PL_HttpCertStoreContext *context = NULL;
61 
62         PKIX_ENTER
63                 (HTTPCERTSTORECONTEXT, "pkix_pl_HttpCertStoreContext_Destroy");
64         PKIX_NULLCHECK_ONE(object);
65 
66         PKIX_CHECK(pkix_CheckType
67                     (object, PKIX_HTTPCERTSTORECONTEXT_TYPE, plContext),
68                     PKIX_OBJECTNOTANHTTPCERTSTORECONTEXT);
69 
70         context = (PKIX_PL_HttpCertStoreContext *)object;
71         hcv1 = (const SEC_HttpClientFcnV1 *)(context->client);
72         if (context->requestSession != NULL) {
73             (*hcv1->freeFcn)(context->requestSession);
74             context->requestSession = NULL;
75         }
76         if (context->serverSession != NULL) {
77             (*hcv1->freeSessionFcn)(context->serverSession);
78             context->serverSession = NULL;
79         }
80         if (context->path != NULL) {
81             PORT_Free(context->path);
82             context->path = NULL;
83         }
84 
85 cleanup:
86 
87         PKIX_RETURN(HTTPCERTSTORECONTEXT);
88 }
89 
90 /*
91  * FUNCTION: pkix_pl_HttpCertStoreContext_RegisterSelf
92  *
93  * DESCRIPTION:
94  *  Registers PKIX_PL_HTTPCERTSTORECONTEXT_TYPE and its related
95  *  functions with systemClasses[]
96  *
97  * THREAD SAFETY:
98  *  Not Thread Safe - for performance and complexity reasons
99  *
100  *  Since this function is only called by PKIX_PL_Initialize, which should
101  *  only be called once, it is acceptable that this function is not
102  *  thread-safe.
103  */
104 PKIX_Error *
pkix_pl_HttpCertStoreContext_RegisterSelf(void * plContext)105 pkix_pl_HttpCertStoreContext_RegisterSelf(void *plContext)
106 {
107         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
108         pkix_ClassTable_Entry *entry = &systemClasses[PKIX_HTTPCERTSTORECONTEXT_TYPE];
109 
110         PKIX_ENTER(HTTPCERTSTORECONTEXT,
111                 "pkix_pl_HttpCertStoreContext_RegisterSelf");
112 
113         entry->description = "HttpCertStoreContext";
114         entry->typeObjectSize = sizeof(PKIX_PL_HttpCertStoreContext);
115         entry->destructor = pkix_pl_HttpCertStoreContext_Destroy;
116 
117         PKIX_RETURN(HTTPCERTSTORECONTEXT);
118 }
119 
120 
121 /* --Private-Http-CertStore-Database-Functions----------------------- */
122 
123 typedef struct callbackContextStruct  {
124         PKIX_List  *pkixCertList;
125         PKIX_Error *error;
126         void       *plContext;
127 } callbackContext;
128 
129 
130 /*
131  * FUNCTION: certCallback
132  * DESCRIPTION:
133  *
134  *  This function processes the null-terminated array of SECItems produced by
135  *  extracting the contents of a signedData message received in response to an
136  *  HTTP cert query. Its address is supplied as a callback function to
137  *  CERT_DecodeCertPackage; it is not expected to be called directly.
138  *
139  *  Note that it does not conform to the libpkix API standard of returning
140  *  a PKIX_Error*. It returns a SECStatus.
141  *
142  * PARAMETERS:
143  *  "arg"
144  *      The address of the callbackContext provided as a void* argument to
145  *      CERT_DecodeCertPackage. Must be non-NULL.
146  *  "secitemCerts"
147  *      The address of the null-terminated array of SECItems. Must be non-NULL.
148  *  "numcerts"
149  *      The number of SECItems found in the signedData. Must be non-NULL.
150  *  "plContext"
151  *      Platform-specific context pointer.
152  * THREAD SAFETY:
153  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
154  * RETURNS:
155  *  Returns SECSuccess if the function succeeds.
156  *  Returns SECFailure if the function fails.
157  */
158 static SECStatus
certCallback(void * arg,SECItem ** secitemCerts,int numcerts)159 certCallback(void *arg, SECItem **secitemCerts, int numcerts)
160 {
161         callbackContext *cbContext;
162         PKIX_List *pkixCertList = NULL;
163         PKIX_Error *error = NULL;
164         void *plContext = NULL;
165         int itemNum = 0;
166 
167         if ((arg == NULL) || (secitemCerts == NULL)) {
168                 return (SECFailure);
169         }
170 
171         cbContext = (callbackContext *)arg;
172         plContext = cbContext->plContext;
173         pkixCertList = cbContext->pkixCertList;
174 
175         for (; itemNum < numcerts; itemNum++ ) {
176                 error = pkix_pl_Cert_CreateToList(secitemCerts[itemNum],
177                                                   pkixCertList, plContext);
178                 if (error != NULL) {
179                     if (error->errClass == PKIX_FATAL_ERROR) {
180                         cbContext->error = error;
181                         return SECFailure;
182                     }
183                     /* reuse "error" since we could not destruct the old *
184                      * value */
185                     error = PKIX_PL_Object_DecRef((PKIX_PL_Object *)error,
186                                                         plContext);
187                     if (error) {
188                         /* Treat decref failure as a fatal error.
189                          * In this case will leak error, but can not do
190                          * anything about it. */
191                         error->errClass = PKIX_FATAL_ERROR;
192                         cbContext->error = error;
193                         return SECFailure;
194                     }
195                 }
196         }
197 
198         return SECSuccess;
199 }
200 
201 
202 typedef SECStatus (*pkix_DecodeCertsFunc)(char *certbuf, int certlen,
203                                           CERTImportCertificateFunc f, void *arg);
204 
205 
206 struct pkix_DecodeFuncStr {
207     pkix_DecodeCertsFunc func;          /* function pointer to the
208                                          * CERT_DecodeCertPackage function */
209     PRLibrary *smimeLib;                /* Pointer to the smime shared lib*/
210     PRCallOnceType once;
211 };
212 
213 static struct pkix_DecodeFuncStr pkix_decodeFunc;
214 static const PRCallOnceType pkix_pristine;
215 
216 #define SMIME_LIB_NAME SHLIB_PREFIX"smime3."SHLIB_SUFFIX
217 
218 /*
219  * load the smime library and look up the SEC_ReadPKCS7Certs function.
220  *  we do this so we don't have a circular depenency on the smime library,
221  *  and also so we don't have to load the smime library in applications that
222  * don't use it.
223  */
pkix_getDecodeFunction(void)224 static PRStatus PR_CALLBACK pkix_getDecodeFunction(void)
225 {
226     pkix_decodeFunc.smimeLib =
227 		PR_LoadLibrary(SHLIB_PREFIX"smime3."SHLIB_SUFFIX);
228     if (pkix_decodeFunc.smimeLib == NULL) {
229 	return PR_FAILURE;
230     }
231 
232     pkix_decodeFunc.func = (pkix_DecodeCertsFunc) PR_FindFunctionSymbol(
233 		pkix_decodeFunc.smimeLib, "CERT_DecodeCertPackage");
234     if (!pkix_decodeFunc.func) {
235 	return PR_FAILURE;
236     }
237     return PR_SUCCESS;
238 
239 }
240 
241 /*
242  * clears our global state on shutdown.
243  */
244 void
pkix_pl_HttpCertStore_Shutdown(void * plContext)245 pkix_pl_HttpCertStore_Shutdown(void *plContext)
246 {
247     if (pkix_decodeFunc.smimeLib) {
248 	PR_UnloadLibrary(pkix_decodeFunc.smimeLib);
249 	pkix_decodeFunc.smimeLib = NULL;
250     }
251     /* the function pointer just need to be cleared, not freed */
252     pkix_decodeFunc.func = NULL;
253     pkix_decodeFunc.once = pkix_pristine;
254 }
255 
256 /*
257  * This function is based on CERT_DecodeCertPackage from lib/pkcs7/certread.c
258  * read an old style ascii or binary certificate chain
259  */
260 PKIX_Error *
pkix_pl_HttpCertStore_DecodeCertPackage(const char * certbuf,int certlen,CERTImportCertificateFunc f,void * arg,void * plContext)261 pkix_pl_HttpCertStore_DecodeCertPackage
262         (const char *certbuf,
263         int certlen,
264         CERTImportCertificateFunc f,
265         void *arg,
266         void *plContext)
267 {
268 
269         PRStatus status;
270         SECStatus rv;
271 
272         PKIX_ENTER
273                 (HTTPCERTSTORECONTEXT,
274                 "pkix_pl_HttpCertStore_DecodeCertPackage");
275         PKIX_NULLCHECK_TWO(certbuf, f);
276 
277         status = PR_CallOnce(&pkix_decodeFunc.once, pkix_getDecodeFunction);
278 
279         if (status != PR_SUCCESS) {
280                PKIX_ERROR(PKIX_CANTLOADLIBSMIME);
281         }
282 
283         /* paranoia, shouldn't happen if status == PR_SUCCESS); */
284         if (!pkix_decodeFunc.func) {
285                PKIX_ERROR(PKIX_CANTLOADLIBSMIME);
286         }
287 
288         rv = (*pkix_decodeFunc.func)((char*)certbuf, certlen, f, arg);
289 
290         if (rv != SECSuccess) {
291                 PKIX_ERROR (PKIX_SECREADPKCS7CERTSFAILED);
292         }
293 
294 
295 cleanup:
296 
297         PKIX_RETURN(HTTPCERTSTORECONTEXT);
298 }
299 
300 
301 /*
302  * FUNCTION: pkix_pl_HttpCertStore_ProcessCertResponse
303  * DESCRIPTION:
304  *
305  *  This function verifies that the response code pointed to by "responseCode"
306  *  and the content type pointed to by "responseContentType" are as expected,
307  *  and then decodes the data pointed to by "responseData", of length
308  *  "responseDataLen", into a List of Certs, possibly empty, which is returned
309  *  at "pCertList".
310  *
311  * PARAMETERS:
312  *  "responseCode"
313  *      The value of the HTTP response code.
314  *  "responseContentType"
315  *      The address of the Content-type string. Must be non-NULL.
316  *  "responseData"
317  *      The address of the message data. Must be non-NULL.
318  *  "responseDataLen"
319  *      The length of the message data.
320  *  "pCertList"
321  *      The address of the List that is created. Must be non-NULL.
322  *  "plContext"
323  *      Platform-specific context pointer.
324  * THREAD SAFETY:
325  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
326  * RETURNS:
327  *  Returns NULL if the function succeeds.
328  *  Returns a HttpCertStore Error if the function fails in a non-fatal way.
329  *  Returns a Fatal Error if the function fails in an unrecoverable way.
330  */
331 PKIX_Error *
pkix_pl_HttpCertStore_ProcessCertResponse(PRUint16 responseCode,const char * responseContentType,const char * responseData,PRUint32 responseDataLen,PKIX_List ** pCertList,void * plContext)332 pkix_pl_HttpCertStore_ProcessCertResponse(
333         PRUint16 responseCode,
334         const char *responseContentType,
335         const char *responseData,
336         PRUint32 responseDataLen,
337         PKIX_List **pCertList,
338         void *plContext)
339 {
340         callbackContext cbContext;
341 
342         PKIX_ENTER(HTTPCERTSTORECONTEXT,
343                 "pkix_pl_HttpCertStore_ProcessCertResponse");
344 
345         cbContext.error = NULL;
346         cbContext.plContext = plContext;
347         cbContext.pkixCertList = NULL;
348 
349         PKIX_NULLCHECK_ONE(pCertList);
350 
351         if (responseCode != 200) {
352                 PKIX_ERROR(PKIX_BADHTTPRESPONSE);
353         }
354 
355         /* check that response type is application/pkcs7-mime */
356         if (responseContentType == NULL) {
357                 PKIX_ERROR(PKIX_NOCONTENTTYPEINHTTPRESPONSE);
358         }
359 
360         if (responseData == NULL) {
361                 PKIX_ERROR(PKIX_NORESPONSEDATAINHTTPRESPONSE);
362         }
363 
364         PKIX_CHECK(
365             PKIX_List_Create(&cbContext.pkixCertList, plContext),
366             PKIX_LISTCREATEFAILED);
367 
368         PKIX_CHECK_ONLY_FATAL(
369             pkix_pl_HttpCertStore_DecodeCertPackage(responseData,
370                                                     responseDataLen,
371                                                     certCallback,
372                                                     &cbContext,
373                                                     plContext),
374             PKIX_HTTPCERTSTOREDECODECERTPACKAGEFAILED);
375         if (cbContext.error) {
376             /* Aborting on a fatal error(See certCallback fn) */
377             pkixErrorResult = cbContext.error;
378             goto cleanup;
379         }
380 
381         *pCertList = cbContext.pkixCertList;
382         cbContext.pkixCertList = NULL;
383 
384 cleanup:
385 
386         PKIX_DECREF(cbContext.pkixCertList);
387 
388         PKIX_RETURN(HTTPCERTSTORECONTEXT);
389 }
390 
391 /*
392  * FUNCTION: pkix_pl_HttpCertStore_ProcessCrlResponse
393  * DESCRIPTION:
394  *
395  *  This function verifies that the response code pointed to by "responseCode"
396  *  and the content type pointed to by "responseContentType" are as expected,
397  *  and then decodes the data pointed to by "responseData", of length
398  *  "responseDataLen", into a List of Crls, possibly empty, which is returned
399  *  at "pCrlList".
400  *
401  * PARAMETERS:
402  *  "responseCode"
403  *      The value of the HTTP response code.
404  *  "responseContentType"
405  *      The address of the Content-type string. Must be non-NULL.
406  *  "responseData"
407  *      The address of the message data. Must be non-NULL.
408  *  "responseDataLen"
409  *      The length of the message data.
410  *  "pCrlList"
411  *      The address of the List that is created. Must be non-NULL.
412  *  "plContext"
413  *      Platform-specific context pointer.
414  * THREAD SAFETY:
415  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
416  * RETURNS:
417  *  Returns NULL if the function succeeds.
418  *  Returns a HttpCertStore Error if the function fails in a non-fatal way.
419  *  Returns a Fatal Error if the function fails in an unrecoverable way.
420  */
421 PKIX_Error *
pkix_pl_HttpCertStore_ProcessCrlResponse(PRUint16 responseCode,const char * responseContentType,const char * responseData,PRUint32 responseDataLen,PKIX_List ** pCrlList,void * plContext)422 pkix_pl_HttpCertStore_ProcessCrlResponse(
423         PRUint16 responseCode,
424         const char *responseContentType,
425         const char *responseData,
426         PRUint32 responseDataLen,
427         PKIX_List **pCrlList,
428         void *plContext)
429 {
430         SECItem encodedResponse;
431         PRInt16 compareVal = 0;
432         PKIX_List *crls = NULL;
433         SECItem *derCrlCopy = NULL;
434         CERTSignedCrl *nssCrl = NULL;
435         PKIX_PL_CRL *crl = NULL;
436 
437         PKIX_ENTER(HTTPCERTSTORECONTEXT,
438                 "pkix_pl_HttpCertStore_ProcessCrlResponse");
439         PKIX_NULLCHECK_ONE(pCrlList);
440 
441         if (responseCode != 200) {
442                 PKIX_ERROR(PKIX_BADHTTPRESPONSE);
443         }
444 
445         /* check that response type is application/pkix-crl */
446         if (responseContentType == NULL) {
447                 PKIX_ERROR(PKIX_NOCONTENTTYPEINHTTPRESPONSE);
448         }
449 
450         compareVal = PORT_Strcasecmp(responseContentType,
451                                      "application/pkix-crl");
452         if (compareVal != 0) {
453                 PKIX_ERROR(PKIX_CONTENTTYPENOTPKIXCRL);
454         }
455         encodedResponse.type = siBuffer;
456         encodedResponse.data = (void*)responseData;
457         encodedResponse.len = responseDataLen;
458 
459         derCrlCopy = SECITEM_DupItem(&encodedResponse);
460         if (!derCrlCopy) {
461             PKIX_ERROR(PKIX_ALLOCERROR);
462         }
463         /* crl will be based on derCrlCopy, but will not own the der. */
464         nssCrl =
465             CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, SEC_CRL_TYPE,
466                                        CRL_DECODE_DONT_COPY_DER |
467                                        CRL_DECODE_SKIP_ENTRIES);
468         if (!nssCrl) {
469             PKIX_ERROR(PKIX_FAILEDTODECODECRL);
470         }
471         /* pkix crls own the der. */
472         PKIX_CHECK(
473             pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy, NULL,
474                                             &crl, plContext),
475             PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
476         /* Left control over memory pointed by derCrlCopy and
477          * nssCrl to pkix crl. */
478         derCrlCopy = NULL;
479         nssCrl = NULL;
480         PKIX_CHECK(PKIX_List_Create(&crls, plContext),
481                    PKIX_LISTCREATEFAILED);
482         PKIX_CHECK(PKIX_List_AppendItem
483                    (crls, (PKIX_PL_Object *) crl, plContext),
484                    PKIX_LISTAPPENDITEMFAILED);
485         *pCrlList = crls;
486         crls = NULL;
487 cleanup:
488         if (derCrlCopy) {
489             SECITEM_FreeItem(derCrlCopy, PR_TRUE);
490         }
491         if (nssCrl) {
492             SEC_DestroyCrl(nssCrl);
493         }
494         PKIX_DECREF(crl);
495         PKIX_DECREF(crls);
496 
497         PKIX_RETURN(HTTPCERTSTORECONTEXT);
498 }
499 
500 /*
501  * FUNCTION: pkix_pl_HttpCertStore_CreateRequestSession
502  * DESCRIPTION:
503  *
504  *  This function takes elements from the HttpCertStoreContext pointed to by
505  *  "context" (path, client, and serverSession) and creates a RequestSession.
506  *  See the HTTPClient API described in ocspt.h for further details.
507  *
508  * PARAMETERS:
509  *  "context"
510  *      The address of the HttpCertStoreContext. Must be non-NULL.
511  *  "plContext"
512  *      Platform-specific context pointer.
513  * THREAD SAFETY:
514  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
515  * RETURNS:
516  *  Returns NULL if the function succeeds.
517  *  Returns a HttpCertStore Error if the function fails in a non-fatal way.
518  *  Returns a Fatal Error if the function fails in an unrecoverable way.
519  */
520 PKIX_Error *
pkix_pl_HttpCertStore_CreateRequestSession(PKIX_PL_HttpCertStoreContext * context,void * plContext)521 pkix_pl_HttpCertStore_CreateRequestSession(
522         PKIX_PL_HttpCertStoreContext *context,
523         void *plContext)
524 {
525         const SEC_HttpClientFcnV1 *hcv1 = NULL;
526         SECStatus rv = SECFailure;
527 
528         PKIX_ENTER
529                 (HTTPCERTSTORECONTEXT,
530                 "pkix_pl_HttpCertStore_CreateRequestSession");
531         PKIX_NULLCHECK_TWO(context, context->serverSession);
532 
533         if (context->client->version != 1) {
534                 PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
535         }
536 
537         hcv1 = &(context->client->fcnTable.ftable1);
538         if (context->requestSession != NULL) {
539             (*hcv1->freeFcn)(context->requestSession);
540             context->requestSession = 0;
541         }
542 
543         rv = (*hcv1->createFcn)(context->serverSession, "http",
544                          context->path, "GET",
545                          PR_SecondsToInterval(
546                              ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
547                          &(context->requestSession));
548 
549         if (rv != SECSuccess) {
550             PKIX_ERROR(PKIX_HTTPSERVERERROR);
551         }
552 cleanup:
553 
554         PKIX_RETURN(HTTPCERTSTORECONTEXT);
555 
556 }
557 
558 /*
559  * FUNCTION: pkix_pl_HttpCertStore_GetCert
560  *  (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
561  */
562 PKIX_Error *
pkix_pl_HttpCertStore_GetCert(PKIX_CertStore * store,PKIX_CertSelector * selector,PKIX_VerifyNode * verifyNode,void ** pNBIOContext,PKIX_List ** pCertList,void * plContext)563 pkix_pl_HttpCertStore_GetCert(
564         PKIX_CertStore *store,
565         PKIX_CertSelector *selector,
566         PKIX_VerifyNode *verifyNode,
567         void **pNBIOContext,
568         PKIX_List **pCertList,
569         void *plContext)
570 {
571         const SEC_HttpClientFcnV1 *hcv1 = NULL;
572         PKIX_PL_HttpCertStoreContext *context = NULL;
573         void *nbioContext = NULL;
574         SECStatus rv = SECFailure;
575         PRUint16 responseCode = 0;
576         const char *responseContentType = NULL;
577         const char *responseData = NULL;
578         PRUint32 responseDataLen = 0;
579         PKIX_List *certList = NULL;
580 
581         PKIX_ENTER(HTTPCERTSTORECONTEXT, "pkix_pl_HttpCertStore_GetCert");
582         PKIX_NULLCHECK_THREE(store, selector, pCertList);
583 
584         nbioContext = *pNBIOContext;
585         *pNBIOContext = NULL;
586 
587         PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
588                 (store, (PKIX_PL_Object **)&context, plContext),
589                 PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
590 
591         if (context->client->version != 1) {
592             PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
593         }
594 
595         hcv1 = &(context->client->fcnTable.ftable1);
596 
597         PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession
598                    (context, plContext),
599                    PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED);
600 
601         responseDataLen =
602             ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
603 
604         rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession,
605                                         (PRPollDesc **)&nbioContext,
606                                         &responseCode,
607                                         (const char **)&responseContentType,
608                                         NULL, /* &responseHeaders */
609                                         (const char **)&responseData,
610                                         &responseDataLen);
611         if (rv != SECSuccess) {
612             PKIX_ERROR(PKIX_HTTPSERVERERROR);
613         }
614 
615         if (nbioContext != 0) {
616             *pNBIOContext = nbioContext;
617             goto cleanup;
618         }
619 
620         PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse
621                 (responseCode,
622                 responseContentType,
623                 responseData,
624                 responseDataLen,
625                 &certList,
626                 plContext),
627                 PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED);
628 
629         *pCertList = certList;
630 
631 cleanup:
632         PKIX_DECREF(context);
633 
634         PKIX_RETURN(CERTSTORE);
635 }
636 
637 /*
638  * FUNCTION: pkix_pl_HttpCertStore_GetCertContinue
639  *  (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
640  */
641 PKIX_Error *
pkix_pl_HttpCertStore_GetCertContinue(PKIX_CertStore * store,PKIX_CertSelector * selector,PKIX_VerifyNode * verifyNode,void ** pNBIOContext,PKIX_List ** pCertList,void * plContext)642 pkix_pl_HttpCertStore_GetCertContinue(
643         PKIX_CertStore *store,
644         PKIX_CertSelector *selector,
645         PKIX_VerifyNode *verifyNode,
646         void **pNBIOContext,
647         PKIX_List **pCertList,
648         void *plContext)
649 {
650         const SEC_HttpClientFcnV1 *hcv1 = NULL;
651         PKIX_PL_HttpCertStoreContext *context = NULL;
652         void *nbioContext = NULL;
653         SECStatus rv = SECFailure;
654         PRUint16 responseCode = 0;
655         const char *responseContentType = NULL;
656         const char *responseData = NULL;
657         PRUint32 responseDataLen = 0;
658         PKIX_List *certList = NULL;
659 
660         PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCertContinue");
661         PKIX_NULLCHECK_THREE(store, selector, pCertList);
662 
663         nbioContext = *pNBIOContext;
664         *pNBIOContext = NULL;
665 
666         PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
667                 (store, (PKIX_PL_Object **)&context, plContext),
668                 PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
669 
670         if (context->client->version != 1) {
671                 PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
672         }
673 
674         hcv1 = &(context->client->fcnTable.ftable1);
675         PKIX_NULLCHECK_ONE(context->requestSession);
676 
677         responseDataLen =
678             ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
679 
680         rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession,
681                         (PRPollDesc **)&nbioContext,
682                         &responseCode,
683                         (const char **)&responseContentType,
684                         NULL, /* &responseHeaders */
685                         (const char **)&responseData,
686                         &responseDataLen);
687 
688         if (rv != SECSuccess) {
689             PKIX_ERROR(PKIX_HTTPSERVERERROR);
690         }
691 
692         if (nbioContext != 0) {
693             *pNBIOContext = nbioContext;
694             goto cleanup;
695         }
696 
697         PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse
698                 (responseCode,
699                 responseContentType,
700                 responseData,
701                 responseDataLen,
702                 &certList,
703                 plContext),
704                 PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED);
705 
706         *pCertList = certList;
707 
708 cleanup:
709         PKIX_DECREF(context);
710 
711         PKIX_RETURN(CERTSTORE);
712 }
713 
714 /*
715  * FUNCTION: pkix_pl_HttpCertStore_GetCRL
716  *  (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
717  */
718 PKIX_Error *
pkix_pl_HttpCertStore_GetCRL(PKIX_CertStore * store,PKIX_CRLSelector * selector,void ** pNBIOContext,PKIX_List ** pCrlList,void * plContext)719 pkix_pl_HttpCertStore_GetCRL(
720         PKIX_CertStore *store,
721         PKIX_CRLSelector *selector,
722         void **pNBIOContext,
723         PKIX_List **pCrlList,
724         void *plContext)
725 {
726 
727         const SEC_HttpClientFcnV1 *hcv1 = NULL;
728         PKIX_PL_HttpCertStoreContext *context = NULL;
729         void *nbioContext = NULL;
730         SECStatus rv = SECFailure;
731         PRUint16 responseCode = 0;
732         const char *responseContentType = NULL;
733         const char *responseData = NULL;
734         PRUint32 responseDataLen = 0;
735         PKIX_List *crlList = NULL;
736 
737         PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCRL");
738         PKIX_NULLCHECK_THREE(store, selector, pCrlList);
739 
740         nbioContext = *pNBIOContext;
741         *pNBIOContext = NULL;
742 
743         PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
744                 (store, (PKIX_PL_Object **)&context, plContext),
745                 PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
746 
747         if (context->client->version != 1) {
748                 PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
749         }
750 
751         hcv1 = &(context->client->fcnTable.ftable1);
752         PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession
753                    (context, plContext),
754                    PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED);
755 
756         responseDataLen =
757             ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
758 
759         rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession,
760                         (PRPollDesc **)&nbioContext,
761                         &responseCode,
762                         (const char **)&responseContentType,
763                         NULL, /* &responseHeaders */
764                         (const char **)&responseData,
765                         &responseDataLen);
766 
767         if (rv != SECSuccess) {
768             PKIX_ERROR(PKIX_HTTPSERVERERROR);
769         }
770 
771         if (nbioContext != 0) {
772             *pNBIOContext = nbioContext;
773             goto cleanup;
774         }
775 
776         PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCrlResponse
777                 (responseCode,
778                 responseContentType,
779                 responseData,
780                 responseDataLen,
781                 &crlList,
782                 plContext),
783                 PKIX_HTTPCERTSTOREPROCESSCRLRESPONSEFAILED);
784 
785         *pCrlList = crlList;
786 
787 cleanup:
788         PKIX_DECREF(context);
789 
790         PKIX_RETURN(CERTSTORE);
791 }
792 
793 /*
794  * FUNCTION: pkix_pl_HttpCertStore_GetCRLContinue
795  *  (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
796  */
797 PKIX_Error *
pkix_pl_HttpCertStore_GetCRLContinue(PKIX_CertStore * store,PKIX_CRLSelector * selector,void ** pNBIOContext,PKIX_List ** pCrlList,void * plContext)798 pkix_pl_HttpCertStore_GetCRLContinue(
799         PKIX_CertStore *store,
800         PKIX_CRLSelector *selector,
801         void **pNBIOContext,
802         PKIX_List **pCrlList,
803         void *plContext)
804 {
805         const SEC_HttpClientFcnV1 *hcv1 = NULL;
806         PKIX_PL_HttpCertStoreContext *context = NULL;
807         void *nbioContext = NULL;
808         SECStatus rv = SECFailure;
809         PRUint16 responseCode = 0;
810         const char *responseContentType = NULL;
811         const char *responseData = NULL;
812         PRUint32 responseDataLen = 0;
813         PKIX_List *crlList = NULL;
814 
815         PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCRLContinue");
816         PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList);
817 
818         nbioContext = *pNBIOContext;
819         *pNBIOContext = NULL;
820 
821         PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
822                 (store, (PKIX_PL_Object **)&context, plContext),
823                 PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
824 
825         if (context->client->version != 1) {
826             PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
827         }
828         hcv1 = &(context->client->fcnTable.ftable1);
829 
830         PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession
831                    (context, plContext),
832                    PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED);
833 
834         responseDataLen =
835             ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
836 
837         rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession,
838                         (PRPollDesc **)&nbioContext,
839                         &responseCode,
840                         (const char **)&responseContentType,
841                         NULL, /* &responseHeaders */
842                         (const char **)&responseData,
843                         &responseDataLen);
844 
845         if (rv != SECSuccess) {
846             PKIX_ERROR(PKIX_HTTPSERVERERROR);
847         }
848 
849         if (nbioContext != 0) {
850             *pNBIOContext = nbioContext;
851             goto cleanup;
852         }
853 
854         PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCrlResponse
855                 (responseCode,
856                 responseContentType,
857                 responseData,
858                 responseDataLen,
859                 &crlList,
860                 plContext),
861                 PKIX_HTTPCERTSTOREPROCESSCRLRESPONSEFAILED);
862 
863         *pCrlList = crlList;
864 
865 cleanup:
866         PKIX_DECREF(context);
867 
868         PKIX_RETURN(CERTSTORE);
869 }
870 
871 /* --Public-HttpCertStore-Functions----------------------------------- */
872 
873 /*
874  * FUNCTION: pkix_pl_HttpCertStore_CreateWithAsciiName
875  * DESCRIPTION:
876  *
877  *  This function uses the HttpClient pointed to by "client" and the string
878  *  (hostname:portnum/path, with portnum optional) pointed to by "locationAscii"
879  *  to create an HttpCertStore connected to the desired location, storing the
880  *  created CertStore at "pCertStore".
881  *
882  * PARAMETERS:
883  *  "client"
884  *      The address of the HttpClient. Must be non-NULL.
885  *  "locationAscii"
886  *      The address of the character string indicating the hostname, port, and
887  *      path to be queried for Certs or Crls. Must be non-NULL.
888  *  "pCertStore"
889  *      The address in which the object is stored. Must be non-NULL.
890  *  "plContext"
891  *      Platform-specific context pointer.
892  * THREAD SAFETY:
893  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
894  * RETURNS:
895  *  Returns NULL if the function succeeds.
896  *  Returns a HttpCertStore Error if the function fails in a non-fatal way.
897  *  Returns a Fatal Error if the function fails in an unrecoverable way.
898  */
899 PKIX_Error *
pkix_pl_HttpCertStore_CreateWithAsciiName(PKIX_PL_HttpClient * client,char * locationAscii,PKIX_CertStore ** pCertStore,void * plContext)900 pkix_pl_HttpCertStore_CreateWithAsciiName(
901         PKIX_PL_HttpClient *client,
902         char *locationAscii,
903         PKIX_CertStore **pCertStore,
904         void *plContext)
905 {
906         const SEC_HttpClientFcn *clientFcn = NULL;
907         const SEC_HttpClientFcnV1 *hcv1 = NULL;
908         PKIX_PL_HttpCertStoreContext *httpCertStore = NULL;
909         PKIX_CertStore *certStore = NULL;
910         char *hostname = NULL;
911         char *path = NULL;
912         PRUint16 port = 0;
913         SECStatus rv = SECFailure;
914 
915         PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_CreateWithAsciiName");
916         PKIX_NULLCHECK_TWO(locationAscii, pCertStore);
917 
918         if (client == NULL) {
919                 clientFcn = SEC_GetRegisteredHttpClient();
920                 if (clientFcn == NULL) {
921                         PKIX_ERROR(PKIX_NOREGISTEREDHTTPCLIENT);
922                 }
923         } else {
924                 clientFcn = (const SEC_HttpClientFcn *)client;
925         }
926 
927         if (clientFcn->version != 1) {
928                 PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
929         }
930 
931         /* create a PKIX_PL_HttpCertStore object */
932         PKIX_CHECK(PKIX_PL_Object_Alloc
933                   (PKIX_HTTPCERTSTORECONTEXT_TYPE,
934                   sizeof (PKIX_PL_HttpCertStoreContext),
935                   (PKIX_PL_Object **)&httpCertStore,
936                   plContext),
937                   PKIX_COULDNOTCREATEOBJECT);
938 
939         /* Initialize fields */
940         httpCertStore->client = clientFcn; /* not a PKIX object! */
941 
942         /* parse location -> hostname, port, path */
943         rv = CERT_ParseURL(locationAscii, &hostname, &port, &path);
944         if (rv == SECFailure || hostname == NULL || path == NULL) {
945                 PKIX_ERROR(PKIX_URLPARSINGFAILED);
946         }
947 
948         httpCertStore->path = path;
949         path = NULL;
950 
951         hcv1 = &(clientFcn->fcnTable.ftable1);
952         rv = (*hcv1->createSessionFcn)(hostname, port,
953                                        &(httpCertStore->serverSession));
954         if (rv != SECSuccess) {
955             PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED);
956         }
957 
958         httpCertStore->requestSession = NULL;
959 
960         PKIX_CHECK(PKIX_CertStore_Create
961                 (pkix_pl_HttpCertStore_GetCert,
962                 pkix_pl_HttpCertStore_GetCRL,
963                 pkix_pl_HttpCertStore_GetCertContinue,
964                 pkix_pl_HttpCertStore_GetCRLContinue,
965                 NULL,       /* don't support trust */
966                 NULL,      /* can not store crls */
967                 NULL,      /* can not do revocation check */
968                 (PKIX_PL_Object *)httpCertStore,
969                 PKIX_TRUE,  /* cache flag */
970                 PKIX_FALSE, /* not local */
971                 &certStore,
972                 plContext),
973                 PKIX_CERTSTORECREATEFAILED);
974 
975         *pCertStore = certStore;
976         certStore = NULL;
977 
978 cleanup:
979         PKIX_DECREF(httpCertStore);
980         if (hostname) {
981             PORT_Free(hostname);
982         }
983         if (path) {
984             PORT_Free(path);
985         }
986 
987         PKIX_RETURN(CERTSTORE);
988 }
989 
990 /*
991  * FUNCTION: PKIX_PL_HttpCertStore_Create
992  * (see comments in pkix_samples_modules.h)
993  */
994 PKIX_Error *
PKIX_PL_HttpCertStore_Create(PKIX_PL_HttpClient * client,PKIX_PL_GeneralName * location,PKIX_CertStore ** pCertStore,void * plContext)995 PKIX_PL_HttpCertStore_Create(
996         PKIX_PL_HttpClient *client,
997         PKIX_PL_GeneralName *location,
998         PKIX_CertStore **pCertStore,
999         void *plContext)
1000 {
1001         PKIX_PL_String *locationString = NULL;
1002         char *locationAscii = NULL;
1003         PKIX_UInt32 len = 0;
1004 
1005         PKIX_ENTER(CERTSTORE, "PKIX_PL_HttpCertStore_Create");
1006         PKIX_NULLCHECK_TWO(location, pCertStore);
1007 
1008         PKIX_TOSTRING(location, &locationString, plContext,
1009                 PKIX_GENERALNAMETOSTRINGFAILED);
1010 
1011         PKIX_CHECK(PKIX_PL_String_GetEncoded
1012                 (locationString,
1013                 PKIX_ESCASCII,
1014                 (void **)&locationAscii,
1015                 &len,
1016                 plContext),
1017                 PKIX_STRINGGETENCODEDFAILED);
1018 
1019         PKIX_CHECK(pkix_pl_HttpCertStore_CreateWithAsciiName
1020                 (client, locationAscii, pCertStore, plContext),
1021                 PKIX_HTTPCERTSTORECREATEWITHASCIINAMEFAILED);
1022 
1023 cleanup:
1024 
1025         PKIX_DECREF(locationString);
1026 
1027         PKIX_RETURN(CERTSTORE);
1028 }
1029 
1030 /*
1031  * FUNCTION: pkix_HttpCertStore_FindSocketConnection
1032  * DESCRIPTION:
1033  *
1034         PRIntervalTime timeout,
1035         char *hostname,
1036         PRUint16 portnum,
1037         PRErrorCode *pStatus,
1038         PKIX_PL_Socket **pSocket,
1039 
1040  *  This function checks for an existing socket, creating a new one if unable
1041  *  to find an existing one, for the host pointed to by "hostname" and the port
1042  *  pointed to by "portnum". If a new socket is created the PRIntervalTime in
1043  *  "timeout" will be used for the timeout value and a creation status is
1044  *  returned at "pStatus". The address of the socket is stored at "pSocket".
1045  *
1046  * PARAMETERS:
1047  *  "timeout"
1048  *      The PRIntervalTime of the timeout value.
1049  *  "hostname"
1050  *      The address of the string containing the hostname. Must be non-NULL.
1051  *  "portnum"
1052  *      The port number for the desired socket.
1053  *  "pStatus"
1054  *      The address at which the status is stored. Must be non-NULL.
1055  *  "pSocket"
1056  *      The address at which the socket is stored. Must be non-NULL.
1057  *  "plContext"
1058  *      Platform-specific context pointer.
1059  * THREAD SAFETY:
1060  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
1061  * RETURNS:
1062  *  Returns NULL if the function succeeds.
1063  *  Returns a HttpCertStore Error if the function fails in a non-fatal way.
1064  *  Returns a Fatal Error if the function fails in an unrecoverable way.
1065  */
1066 PKIX_Error *
pkix_HttpCertStore_FindSocketConnection(PRIntervalTime timeout,char * hostname,PRUint16 portnum,PRErrorCode * pStatus,PKIX_PL_Socket ** pSocket,void * plContext)1067 pkix_HttpCertStore_FindSocketConnection(
1068         PRIntervalTime timeout,
1069         char *hostname,
1070         PRUint16 portnum,
1071         PRErrorCode *pStatus,
1072         PKIX_PL_Socket **pSocket,
1073         void *plContext)
1074 {
1075         PKIX_PL_String *formatString = NULL;
1076         PKIX_PL_String *hostString = NULL;
1077         PKIX_PL_String *domainString = NULL;
1078         PKIX_PL_Socket *socket = NULL;
1079 
1080         PKIX_ENTER(CERTSTORE, "pkix_HttpCertStore_FindSocketConnection");
1081         PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket);
1082 
1083         *pStatus = 0;
1084 
1085         /* create PKIX_PL_String from hostname and port */
1086         PKIX_CHECK(PKIX_PL_String_Create
1087                 (PKIX_ESCASCII, "%s:%d", 0, &formatString, plContext),
1088                 PKIX_STRINGCREATEFAILED);
1089 
1090 #if 0
1091 hostname = "variation.red.iplanet.com";
1092 portnum = 2001;
1093 #endif
1094 
1095         PKIX_CHECK(PKIX_PL_String_Create
1096                 (PKIX_ESCASCII, hostname, 0, &hostString, plContext),
1097                 PKIX_STRINGCREATEFAILED);
1098 
1099         PKIX_CHECK(PKIX_PL_Sprintf
1100                 (&domainString, plContext, formatString, hostString, portnum),
1101                 PKIX_STRINGCREATEFAILED);
1102 
1103 #ifdef PKIX_SOCKETCACHE
1104         /* Is this domainName already in cache? */
1105         PKIX_CHECK(PKIX_PL_HashTable_Lookup
1106                 (httpSocketCache,
1107                 (PKIX_PL_Object *)domainString,
1108                 (PKIX_PL_Object **)&socket,
1109                 plContext),
1110                 PKIX_HASHTABLELOOKUPFAILED);
1111 #endif
1112         if (socket == NULL) {
1113 
1114                 /* No, create a connection (and cache it) */
1115                 PKIX_CHECK(pkix_pl_Socket_CreateByHostAndPort
1116                         (PKIX_FALSE,       /* create a client, not a server */
1117                         timeout,
1118                         hostname,
1119                         portnum,
1120                         pStatus,
1121                         &socket,
1122                         plContext),
1123                         PKIX_SOCKETCREATEBYHOSTANDPORTFAILED);
1124 
1125 #ifdef PKIX_SOCKETCACHE
1126                 PKIX_CHECK(PKIX_PL_HashTable_Add
1127                         (httpSocketCache,
1128                         (PKIX_PL_Object *)domainString,
1129                         (PKIX_PL_Object *)socket,
1130                         plContext),
1131                         PKIX_HASHTABLEADDFAILED);
1132 #endif
1133         }
1134 
1135         *pSocket = socket;
1136         socket = NULL;
1137 
1138 cleanup:
1139 
1140         PKIX_DECREF(formatString);
1141         PKIX_DECREF(hostString);
1142         PKIX_DECREF(domainString);
1143         PKIX_DECREF(socket);
1144 
1145         PKIX_RETURN(CERTSTORE);
1146 }
1147 
1148