1/* 2 * Copyright (c) 2000,2002,2005-2006 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23/* 24 * ocspdNetwork.cpp - Network support for ocspd and CRL/cert fetch 25 */ 26 27#include <security_ocspd/ocspdDebug.h> 28#include "ocspNetwork.h" 29#include <security_ocspd/ocspdUtils.h> 30#include <CoreFoundation/CoreFoundation.h> 31#include <CoreServices/CoreServices.h> 32#include <security_cdsa_utils/cuEnc64.h> 33#include <stdlib.h> 34#include <Security/cssmapple.h> 35#include <LDAP/ldap.h> 36 37#pragma mark ----- OCSP support ----- 38 39/* POST method has Content-Type header line equal to "application/ocsp-request" */ 40static CFStringRef kContentType = CFSTR("Content-Type"); 41static CFStringRef kAppOcspRequest = CFSTR("application/ocsp-request"); 42 43#ifndef NDEBUG 44#define DUMP_BLOBS 0 45#else 46#define DUMP_BLOBS 0 47#endif 48 49#define OCSP_GET_FILE "/tmp/ocspGet" 50#define OCSP_RESP_FILE "/tmp/ocspResp" 51 52#if DUMP_BLOBS 53 54#include <security_cdsa_utils/cuFileIo.h> 55 56static void writeBlob( 57 const char *fileName, 58 const char *whatIsIt, 59 const unsigned char *data, 60 unsigned dataLen) 61{ 62 if(writeFile(fileName, data, dataLen)) { 63 printf("***Error writing %s to %s\n", whatIsIt, fileName); 64 } 65 else { 66 printf("...wrote %u bytes of %s to %s\n", dataLen, whatIsIt, fileName); 67 } 68} 69 70#else 71 72#define writeBlob(f,w,d,l) 73 74#endif /* DUMP_BLOBS */ 75 76/* fetch via HTTP POST */ 77 78#define POST_BUFSIZE 1024 79 80CSSM_RETURN ocspdHttpPost( 81 SecAsn1CoderRef coder, 82 const CSSM_DATA &url, 83 const CSSM_DATA &ocspReq, // DER encoded 84 CSSM_DATA &fetched) // mallocd in coder space and RETURNED 85{ 86 CSSM_RETURN ourRtn = CSSM_OK; 87 CFIndex thisMove; 88 UInt8 inBuf[POST_BUFSIZE]; 89 /* resources to release on exit */ 90 CFMutableDataRef inData = NULL; 91 CFReadStreamRef cfStream = NULL; 92 CFHTTPMessageRef request = NULL; 93 CFDataRef postData = NULL; 94 CFURLRef cfUrl = NULL; 95 96 /* trim off possible NULL terminator from incoming URL */ 97 uint32 urlLen = url.Length; 98 if(url.Data[urlLen - 1] == '\0') { 99 urlLen--; 100 } 101 102 cfUrl = CFURLCreateWithBytes(NULL, 103 url.Data, urlLen, 104 kCFStringEncodingUTF8, // right? 105 NULL); // this is absolute path 106 if(cfUrl == NULL) { 107 ocspdErrorLog("CFURLCreateWithBytes returned NULL\n"); 108 /* FIXME..? */ 109 return CSSMERR_APPLETP_CRL_BAD_URI; 110 } 111 /* subsequent errors to errOut: */ 112 113 #ifndef NDEBUG 114 { 115 char *ustr = (char *)malloc(urlLen + 1); 116 memmove(ustr, url.Data, urlLen); 117 ustr[urlLen] = '\0'; 118 ocspdDebug("ocspdHttpPost: posting to URI %s", ustr); 119 free(ustr); 120 } 121 #endif 122 123 writeBlob(OCSP_GET_FILE, "OCSP Request as POST data", ocspReq.Data, ocspReq.Length); 124 postData = CFDataCreate(NULL, ocspReq.Data, ocspReq.Length); 125 126 /* Create a new HTTP request. */ 127 request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("POST"), cfUrl, 128 kCFHTTPVersion1_1); 129 if (request == NULL) { 130 ocspdErrorLog("ocspdHttpPost: error creating CFHTTPMessage\n"); 131 ourRtn = CSSMERR_TP_INTERNAL_ERROR; 132 goto errOut; 133 } 134 135 // Set the body and required header fields. 136 CFHTTPMessageSetBody(request, postData); 137 CFHTTPMessageSetHeaderFieldValue(request, kContentType, kAppOcspRequest); 138 139 // Create the stream for the request. 140 cfStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request); 141 if (cfStream == NULL) { 142 ocspdErrorLog("ocspdHttpPost: error creating CFReadStream\n"); 143 ourRtn = CSSMERR_TP_INTERNAL_ERROR; 144 goto errOut; 145 } 146 147 /* go, synchronously */ 148 if(!CFReadStreamOpen(cfStream)) { 149 ocspdErrorLog("ocspdHttpPost: error opening CFReadStream\n"); 150 ourRtn = CSSMERR_TP_INTERNAL_ERROR; 151 goto errOut; 152 } 153 inData = CFDataCreateMutable(NULL, 0); 154 for(;;) { 155 thisMove = CFReadStreamRead(cfStream, inBuf, POST_BUFSIZE); 156 if(thisMove < 0) { 157 CFStreamError error = CFReadStreamGetError(cfStream); 158 ocspdErrorLog("ocspdHttpPost: error on CFReadStreamRead: domain " 159 "%ld error %ld\n", (long)error.domain, (long)error.error); 160 ourRtn = CSSMERR_APPLETP_NETWORK_FAILURE; 161 break; 162 } 163 else if(thisMove == 0) { 164 ocspdDebug("ocspdHttpPost: transfer complete, moved %ld bytes", 165 CFDataGetLength(inData)); 166 ourRtn = CSSM_OK; 167 break; 168 } 169 else { 170 CFDataAppendBytes(inData, inBuf, thisMove); 171 } 172 } 173 if(ourRtn == CSSM_OK) { 174 SecAsn1AllocCopy(coder, CFDataGetBytePtr(inData), CFDataGetLength(inData), 175 &fetched); 176 writeBlob(OCSP_RESP_FILE, "OCSP Response", fetched.Data, fetched.Length); 177 } 178 179errOut: 180 CFRELEASE(inData); 181 CFRELEASE(cfStream); 182 CFRELEASE(request); 183 CFRELEASE(postData); 184 CFRELEASE(cfUrl); 185 return ourRtn; 186} 187 188