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