ocspdClient.cpp
1 /* 2 * Copyright (c) 2000,2002,2011-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 /* 25 * ocspdClient.cpp - Client interface to OCSP helper daemon 26 */ 27 28 #include "ocspdClient.h" 29 #include "ocspdTypes.h" 30 #include "ocspdDebug.h" 31 #include <Security/cssmapple.h> 32 #include <security_utilities/threading.h> 33 #include <security_utilities/mach++.h> 34 #include <security_utilities/unix++.h> 35 #ifdef DARLING 36 #include "ocspd.h" 37 #else 38 #include <security_ocspd/ocspd.h> /* MIG interface */ 39 #endif 40 #include <Security/SecBase.h> 41 class ocspdGlobals 42 { 43 public: 44 ocspdGlobals(); 45 ~ocspdGlobals(); 46 void resetServerPort(); 47 mach_port_t serverPort(); 48 private: 49 UnixPlusPlus::ForkMonitor mForkMonitor; 50 MachPlusPlus::Port mServerPort; 51 Mutex mLock; 52 }; 53 54 ocspdGlobals::ocspdGlobals() 55 : mServerPort(0) 56 { 57 /* nothing here, the real work is done in serverPort() */ 58 } 59 60 ocspdGlobals::~ocspdGlobals() 61 { 62 /* I don't believe this should ever execute */ 63 } 64 65 mach_port_t ocspdGlobals::serverPort() 66 { 67 StLock<Mutex> _(mLock); 68 69 // Guard against fork-without-exec. If we are the child of a fork 70 // (that has not exec'ed), our apparent connection to SecurityServer 71 // is just a mirage, and we better reset it. 72 mach_port_t rtnPort = mServerPort.port(); 73 if (mForkMonitor()) { 74 rtnPort = 0; 75 } 76 if(rtnPort != 0) { 77 return rtnPort; 78 } 79 80 const char *serverName = NULL; 81 #ifndef NDEBUG 82 serverName = getenv(OCSPD_BOOTSTRAP_ENV); 83 #endif 84 if(serverName == NULL) { 85 serverName = (char*) OCSPD_BOOTSTRAP_NAME; 86 } 87 try { 88 mServerPort = MachPlusPlus::Bootstrap().lookup2(serverName); 89 } 90 catch(...) { 91 ocspdErrorLog("ocspdGlobals: error contacting server\n"); 92 throw; 93 } 94 return mServerPort; 95 } 96 97 void ocspdGlobals::resetServerPort() 98 { 99 try { 100 mServerPort.deallocate(); 101 } catch(...) { 102 } 103 } 104 105 106 static ModuleNexus<ocspdGlobals> OcspdGlobals; 107 108 /* 109 * Perform network fetch of an OCSP response. Result is not verified in any 110 * way. 111 */ 112 CSSM_RETURN ocspdFetch( 113 Allocator &alloc, 114 const CSSM_DATA &ocspdReq, // DER-encoded SecAsn1OCSPDRequests 115 CSSM_DATA &ocspdResp) // DER-encoded kSecAsn1OCSPDReplies 116 { 117 mach_port_t serverPort = 0; 118 kern_return_t krtn; 119 unsigned char *rtnData = NULL; 120 unsigned rtnLen = 0; 121 122 try { 123 serverPort = OcspdGlobals().serverPort(); 124 } 125 catch(...) { 126 ocspdErrorLog("ocspdFetch: OCSPD server error\n"); 127 return CSSMERR_TP_INTERNAL_ERROR; 128 } 129 130 krtn = ocsp_client_ocspdFetch(serverPort, ocspdReq.Data, (mach_msg_type_number_t)ocspdReq.Length, 131 (void **)&rtnData, &rtnLen); 132 if(krtn) { 133 ocspdErrorLog("ocspdFetch: RPC returned %d\n", krtn); 134 return CSSMERR_APPLETP_OCSP_UNAVAILABLE; 135 } 136 if((rtnData == NULL) || (rtnLen == 0)) { 137 ocspdErrorLog("ocspdFetch: RPC returned NULL data\n"); 138 return CSSMERR_APPLETP_OCSP_UNAVAILABLE; 139 } 140 ocspdResp.Data = (uint8 *)alloc.malloc(rtnLen); 141 ocspdResp.Length = rtnLen; 142 memmove(ocspdResp.Data, rtnData, rtnLen); 143 mig_deallocate((vm_address_t)rtnData, rtnLen); 144 return CSSM_OK; 145 } 146 147 /* 148 * Flush all responses associated with specifed CertID from cache. 149 */ 150 CSSM_RETURN ocspdCacheFlush( 151 const CSSM_DATA &certID) 152 { 153 mach_port_t serverPort = 0; 154 kern_return_t krtn; 155 156 try { 157 serverPort = OcspdGlobals().serverPort(); 158 } 159 catch(...) { 160 ocspdErrorLog("ocspdCacheFlush: OCSPD server error\n"); 161 return CSSMERR_TP_INTERNAL_ERROR; 162 } 163 krtn = ocsp_client_ocspdCacheFlush(serverPort, certID.Data, (mach_msg_type_number_t)certID.Length); 164 if(krtn) { 165 ocspdErrorLog("ocspdCacheFlush: RPC returned %d\n", krtn); 166 return CSSMERR_APPLETP_OCSP_UNAVAILABLE; 167 } 168 return CSSM_OK; 169 } 170 171 /* 172 * Flush stale entries from cache. 173 */ 174 CSSM_RETURN ocspdCacheFlushStale() 175 { 176 mach_port_t serverPort = 0; 177 kern_return_t krtn; 178 179 try { 180 serverPort = OcspdGlobals().serverPort(); 181 } 182 catch(...) { 183 ocspdErrorLog("ocspdCacheFlush: OCSPD server error\n"); 184 return CSSMERR_TP_INTERNAL_ERROR; 185 } 186 krtn = ocsp_client_ocspdCacheFlushStale(serverPort); 187 if(krtn) { 188 if (krtn == MACH_SEND_INVALID_DEST) 189 OcspdGlobals().resetServerPort(); 190 ocspdErrorLog("ocsp_client_ocspdCacheFlushStale: RPC returned %d\n", krtn); 191 return (CSSM_RETURN)krtn; 192 } 193 return CSSM_OK; 194 } 195 196 /* 197 * fetch a certificate from the net. 198 */ 199 CSSM_RETURN ocspdCertFetch( 200 Allocator &alloc, 201 const CSSM_DATA &certURL, 202 CSSM_DATA &certData) // mallocd via alloc and RETURNED 203 { 204 mach_port_t serverPort = 0; 205 kern_return_t krtn; 206 unsigned char *rtnData = NULL; 207 unsigned rtnLen = 0; 208 209 try { 210 serverPort = OcspdGlobals().serverPort(); 211 } 212 catch(...) { 213 ocspdErrorLog("ocspdCertFetch: OCSPD server error\n"); 214 return CSSMERR_TP_INTERNAL_ERROR; 215 } 216 217 krtn = ocsp_client_certFetch(serverPort, certURL.Data, (mach_msg_type_number_t)certURL.Length, 218 (void **)&rtnData, &rtnLen); 219 if(krtn) { 220 if (krtn == MACH_SEND_INVALID_DEST) 221 OcspdGlobals().resetServerPort(); 222 ocspdErrorLog("ocspdCertFetch: RPC returned %d\n", krtn); 223 return CSSMERR_APPLETP_NETWORK_FAILURE; 224 } 225 226 if((rtnData == NULL) || (rtnLen == 0)) { 227 ocspdErrorLog("ocspdCertFetch: RPC returned NULL data\n"); 228 return CSSMERR_APPLETP_CERT_NOT_FOUND_FROM_ISSUER; 229 } 230 certData.Data = (uint8 *)alloc.malloc(rtnLen); 231 certData.Length = rtnLen; 232 memmove(certData.Data, rtnData, rtnLen); 233 mig_deallocate((vm_address_t)rtnData, rtnLen); 234 return CSSM_OK; 235 } 236 237 /* 238 * Fetch a CRL from net with optional cache lookup and store. 239 * verifyTime only used for cache lookup. 240 */ 241 CSSM_RETURN ocspdCRLFetch( 242 Allocator &alloc, 243 const CSSM_DATA &crlURL, 244 const CSSM_DATA *crlIssuer, // optional 245 bool cacheReadEnable, 246 bool cacheWriteEnable, 247 CSSM_TIMESTRING verifyTime, 248 CSSM_DATA &crlData) // mallocd via alloc and RETURNED 249 { 250 mach_port_t serverPort = 0; 251 kern_return_t krtn; 252 unsigned char *rtnData = NULL; 253 unsigned rtnLen = 0; 254 255 if(verifyTime == NULL) { 256 ocspdErrorLog("ocspdCRLFetch: verifyTime NOT OPTIONAL\n"); 257 return CSSMERR_TP_INTERNAL_ERROR; 258 } 259 try { 260 serverPort = OcspdGlobals().serverPort(); 261 } 262 catch(...) { 263 ocspdErrorLog("ocspdCRLFetch: OCSPD server error\n"); 264 return CSSMERR_TP_INTERNAL_ERROR; 265 } 266 267 krtn = ocsp_client_crlFetch(serverPort, crlURL.Data, (mach_msg_type_number_t)crlURL.Length, 268 crlIssuer ? crlIssuer->Data : NULL, crlIssuer ? (mach_msg_type_number_t)crlIssuer->Length : 0, 269 cacheReadEnable, cacheWriteEnable, 270 verifyTime, (mach_msg_type_number_t)strlen(verifyTime), 271 (void **)&rtnData, &rtnLen); 272 if(krtn) { 273 if (krtn == MACH_SEND_INVALID_DEST) 274 OcspdGlobals().resetServerPort(); 275 ocspdErrorLog("ocspdCRLFetch: RPC returned %d\n", krtn); 276 return CSSMERR_APPLETP_NETWORK_FAILURE; 277 } 278 279 if((rtnData == NULL) || (rtnLen == 0)) { 280 ocspdErrorLog("ocspdCRLFetch: RPC returned NULL data\n"); 281 return CSSMERR_APPLETP_CRL_NOT_FOUND; 282 } 283 crlData.Data = (uint8 *)alloc.malloc(rtnLen); 284 crlData.Length = rtnLen; 285 memmove(crlData.Data, rtnData, rtnLen); 286 mig_deallocate((vm_address_t)rtnData, rtnLen); 287 return CSSM_OK; 288 } 289 290 291 /* 292 * Get CRL status for given serial number and issuing entity 293 */ 294 CSSM_RETURN ocspdCRLStatus( 295 const CSSM_DATA &serialNumber, 296 const CSSM_DATA &issuers, 297 const CSSM_DATA *crlIssuer, // optional if URL is supplied 298 const CSSM_DATA *crlURL) // optional if issuer is supplied 299 { 300 mach_port_t serverPort = 0; 301 kern_return_t krtn; 302 303 if(!crlIssuer && !crlURL) { 304 ocspdErrorLog("ocspdCRLStatus: either an issuer or URL is required\n"); 305 return CSSMERR_TP_INTERNAL_ERROR; 306 } 307 try { 308 serverPort = OcspdGlobals().serverPort(); 309 } 310 catch(...) { 311 ocspdErrorLog("ocspdCRLStatus: OCSPD server error\n"); 312 return CSSMERR_TP_INTERNAL_ERROR; 313 } 314 315 krtn = ocsp_client_crlStatus(serverPort, 316 serialNumber.Data, (mach_msg_type_number_t)serialNumber.Length, 317 issuers.Data, (mach_msg_type_number_t)issuers.Length, 318 crlIssuer ? crlIssuer->Data : NULL, crlIssuer ? (mach_msg_type_number_t)crlIssuer->Length : 0, 319 crlURL ? crlURL->Data : NULL, crlURL ? (mach_msg_type_number_t)crlURL->Length : 0); 320 if (krtn == MACH_SEND_INVALID_DEST) { 321 OcspdGlobals().resetServerPort(); 322 } 323 324 return krtn; 325 } 326 327 /* 328 * Refresh the CRL cache. 329 */ 330 CSSM_RETURN ocspdCRLRefresh( 331 unsigned staleDays, 332 unsigned expireOverlapSeconds, 333 bool purgeAll, 334 bool fullCryptoVerify) 335 { 336 mach_port_t serverPort = 0; 337 kern_return_t krtn; 338 try { 339 serverPort = OcspdGlobals().serverPort(); 340 } 341 catch(...) { 342 ocspdErrorLog("ocspdCRLRefresh: OCSPD server error\n"); 343 return CSSMERR_TP_INTERNAL_ERROR; 344 } 345 346 krtn = ocsp_client_crlRefresh(serverPort, staleDays, expireOverlapSeconds, 347 purgeAll, fullCryptoVerify); 348 if(krtn) { 349 if (krtn == MACH_SEND_INVALID_DEST) 350 OcspdGlobals().resetServerPort(); 351 ocspdErrorLog("ocspdCRLRefresh: RPC returned %d\n", krtn); 352 return CSSMERR_APPLETP_NETWORK_FAILURE; 353 } 354 355 return CSSM_OK; 356 } 357 358 /* 359 * Flush all CRLs obtained from specified URL from cache. Called by client when 360 * *it* detects a bad CRL. 361 */ 362 CSSM_RETURN ocspdCRLFlush( 363 const CSSM_DATA &crlURL) 364 { 365 mach_port_t serverPort = 0; 366 kern_return_t krtn; 367 368 try { 369 serverPort = OcspdGlobals().serverPort(); 370 } 371 catch(...) { 372 ocspdErrorLog("ocspdCRLFlush: OCSPD server error\n"); 373 return CSSMERR_TP_INTERNAL_ERROR; 374 } 375 376 krtn = ocsp_client_crlFlush(serverPort, crlURL.Data, (mach_msg_type_number_t)crlURL.Length); 377 if(krtn) { 378 if (krtn == MACH_SEND_INVALID_DEST) 379 OcspdGlobals().resetServerPort(); 380 ocspdErrorLog("ocspdCRLFlush: RPC returned %d\n", krtn); 381 return CSSMERR_APPLETP_NETWORK_FAILURE; 382 } 383 return CSSM_OK; 384 } 385 386 /* 387 * Obtain TrustSettings. 388 */ 389 OSStatus ocspdTrustSettingsRead( 390 Allocator &alloc, 391 SecTrustSettingsDomain domain, 392 CSSM_DATA &trustSettings) // mallocd via alloc and RETURNED 393 { 394 mach_port_t serverPort = 0; 395 kern_return_t krtn; 396 unsigned char *rtnData = NULL; 397 unsigned rtnLen = 0; 398 OSStatus ortn; 399 400 try { 401 serverPort = OcspdGlobals().serverPort(); 402 } 403 catch(...) { 404 ocspdErrorLog("ocspdTrustSettingsRead: OCSPD server error\n"); 405 return errSecInternalComponent; 406 } 407 408 krtn = ocsp_client_trustSettingsRead(serverPort, domain, 409 (void **)&rtnData, &rtnLen, &ortn); 410 if(krtn) { 411 if (krtn == MACH_SEND_INVALID_DEST) 412 OcspdGlobals().resetServerPort(); 413 ocspdErrorLog("ocspdTrustSettingsRead: RPC returned %d\n", krtn); 414 return errSecNotAvailable; 415 } 416 if(ortn) { 417 /* e.g., errSecNoUserTrustRecord */ 418 return ortn; 419 } 420 if((rtnData == NULL) || (rtnLen == 0)) { 421 ocspdErrorLog("ocspdTrustSettingsRead: RPC returned NULL data\n"); 422 return errSecItemNotFound; 423 } 424 trustSettings.Data = (uint8 *)alloc.malloc(rtnLen); 425 trustSettings.Length = rtnLen; 426 memmove(trustSettings.Data, rtnData, rtnLen); 427 mig_deallocate((vm_address_t)rtnData, rtnLen); 428 return errSecSuccess; 429 } 430 431 /* 432 * Write TrustSettings to disk. Results in authentication dialog. 433 */ 434 OSStatus ocspdTrustSettingsWrite( 435 SecTrustSettingsDomain domain, 436 const CSSM_DATA &authBlob, 437 const CSSM_DATA &trustSettings) 438 { 439 mach_port_t serverPort = 0; 440 mach_port_t clientPort = 0; 441 kern_return_t krtn; 442 OSStatus ortn; 443 444 try { 445 serverPort = OcspdGlobals().serverPort(); 446 clientPort = MachPlusPlus::Bootstrap(); 447 } 448 catch(...) { 449 ocspdErrorLog("ocspdTrustSettingsWrite: OCSPD server error\n"); 450 return errSecInternalComponent; 451 } 452 453 krtn = ocsp_client_trustSettingsWrite(serverPort, clientPort, domain, 454 authBlob.Data, (mach_msg_type_number_t)authBlob.Length, 455 trustSettings.Data, (mach_msg_type_number_t)trustSettings.Length, 456 &ortn); 457 if(krtn) { 458 if (krtn == MACH_SEND_INVALID_DEST) 459 OcspdGlobals().resetServerPort(); 460 ocspdErrorLog("ocspdTrustSettingsWrite: RPC returned %d\n", krtn); 461 return errSecInternalComponent; 462 } 463 return ortn; 464 }