5  *  Copyright (c) 2009-2014 Apple Inc.. All Rights Reserved. 
   9  * Copyright (c) 2009-2014 Apple Inc. All Rights Reserved. 
  11  * @APPLE_LICENSE_HEADER_START@ 
  13  * This file contains Original Code and/or Modifications of Original Code 
  14  * as defined in and that are subject to the Apple Public Source License 
  15  * Version 2.0 (the 'License'). You may not use this file except in 
  16  * compliance with the License. Please obtain a copy of the License at 
  17  * http://www.opensource.apple.com/apsl/ and read it before using this 
  20  * The Original Code and all software distributed under the License are 
  21  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  22  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  23  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  24  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  25  * Please see the License for the specific language governing rights and 
  26  * limitations under the License. 
  28  * @APPLE_LICENSE_HEADER_END@ 
  32  * SecCAIssuerRequest.c - asynchronous CAIssuer request fetching engine. 
  36 #include "SecCAIssuerRequest.h" 
  37 #include "SecCAIssuerCache.h" 
  39 #include <Security/SecInternal.h> 
  40 #include <CoreFoundation/CFURL.h> 
  41 #include <CFNetwork/CFHTTPMessage.h> 
  42 #include <utilities/debugging.h> 
  43 #include <Security/SecCertificateInternal.h> 
  44 #include <securityd/asynchttp.h> 
  47 /* CA Issuer lookup code. */ 
  49 typedef struct SecCAIssuerRequest 
*SecCAIssuerRequestRef
; 
  50 struct SecCAIssuerRequest 
{ 
  51     asynchttp_t http
;   /* Must be first field. */ 
  52     SecCertificateRef certificate
; 
  53     CFArrayRef issuers
; /* NONRETAINED */ 
  56     void (*callback
)(void *, CFArrayRef
); 
  59 static void SecCAIssuerRequestRelease(SecCAIssuerRequestRef request
) { 
  60     CFRelease(request
->certificate
); 
  61     asynchttp_free(&request
->http
); 
  65 static bool SecCAIssuerRequestIssue(SecCAIssuerRequestRef request
) { 
  66     while (request
->issuerIX 
< CFArrayGetCount(request
->issuers
)) { 
  67         CFURLRef issuer 
= CFArrayGetValueAtIndex(request
->issuers
, 
  69         CFStringRef scheme 
= CFURLCopyScheme(issuer
); 
  71             if (CFEqual(CFSTR("http"), scheme
)) { 
  72                 CFHTTPMessageRef msg 
= CFHTTPMessageCreateRequest(kCFAllocatorDefault
, 
  73                                                                   CFSTR("GET"), issuer
, kCFHTTPVersion1_1
); 
  75                     secdebug("caissuer", "%@", msg
); 
  76                     bool done 
= asynchttp_request(msg
, &request
->http
); 
  83                 secdebug("caissuer", "failed to get %@", issuer
); 
  85                 secdebug("caissuer", "skipping unsupported uri %@", issuer
); 
  91     /* No more issuers left to try, we're done. */ 
  92     secdebug("caissuer", "no request issued"); 
  93     request
->callback(request
->context
, NULL
); 
  94     SecCAIssuerRequestRelease(request
); 
  98 /* Releases parent unconditionally, and return a CFArrayRef containing 
  99    parent if the normalized subject of parent matches the normalized issuer 
 101 static CFArrayRef 
SecCAIssuerConvertToParents(SecCertificateRef certificate
, 
 102     SecCertificateRef parent
) { 
 103     CFDataRef nic 
= SecCertificateGetNormalizedIssuerContent(certificate
); 
 104     CFArrayRef parents 
= NULL
; 
 106         if (CFEqual(nic
, SecCertificateGetNormalizedSubjectContent(parent
))) { 
 107             const void *ventry 
= parent
; 
 108             parents 
= CFArrayCreate(NULL
, &ventry
, 1, &kCFTypeArrayCallBacks
); 
 115 #define SECONDS_PER_DAY (86400.0) 
 116 static void SecCAIssuerRequestCompleted(asynchttp_t 
*http
, 
 117     CFTimeInterval maxAge
) { 
 118     /* Cast depends on http being first field in struct SecCAIssuerRequest. */ 
 119     SecCAIssuerRequestRef request 
= (SecCAIssuerRequestRef
)http
; 
 120     CFDataRef data 
= (request
->http
.response 
? 
 121         CFHTTPMessageCopyBody(request
->http
.response
) : NULL
); 
 123         SecCertificateRef parent 
= SecCertificateCreateWithData(NULL
, data
); 
 126             /* We keep responses in the cache for at least 7 days, or longer 
 127              if the http response tells us to keep it around for more. */ 
 128             if (maxAge 
< SECONDS_PER_DAY 
* 7) 
 129                 maxAge 
= SECONDS_PER_DAY 
* 7; 
 130             CFAbsoluteTime expires 
= CFAbsoluteTimeGetCurrent() + maxAge
; 
 131             CFURLRef issuer 
= CFArrayGetValueAtIndex(request
->issuers
, 
 132                                                      request
->issuerIX 
- 1); 
 133             SecCAIssuerCacheAddCertificate(parent
, issuer
, expires
); 
 134             CFArrayRef parents 
= SecCAIssuerConvertToParents( 
 135                 request
->certificate
, parent
); 
 137                 secdebug("caissuer", "response: %@ good", http
->response
); 
 138                 request
->callback(request
->context
, parents
); 
 140                 SecCAIssuerRequestRelease(request
); 
 146     secdebug("caissuer", "response: %@ not parent, trying next caissuer", 
 148     SecCAIssuerRequestIssue(request
); 
 151 static CFArrayRef 
SecCAIssuerRequestCacheCopyParents(SecCertificateRef cert
, 
 152     CFArrayRef issuers
) { 
 153     CFIndex ix 
= 0, ex 
= CFArrayGetCount(issuers
); 
 154     for (;ix 
< ex
; ++ix
) { 
 155         CFURLRef issuer 
= CFArrayGetValueAtIndex(issuers
, ix
); 
 156         CFStringRef scheme 
= CFURLCopyScheme(issuer
); 
 158             if (CFEqual(CFSTR("http"), scheme
)) { 
 159                 CFArrayRef parents 
= SecCAIssuerConvertToParents(cert
, 
 160                     SecCAIssuerCacheCopyMatching(issuer
)); 
 162                     secdebug("caissuer", "cache hit, for %@ no request issued", issuer
); 
 173 bool SecCAIssuerCopyParents(SecCertificateRef certificate
, dispatch_queue_t queue
, 
 174     void *context
, void (*callback
)(void *, CFArrayRef
)) { 
 175     CFArrayRef issuers 
= SecCertificateGetCAIssuers(certificate
); 
 177         /* certificate has no caissuer urls, we're done. */ 
 178         callback(context
, NULL
); 
 182     CFArrayRef parents 
= SecCAIssuerRequestCacheCopyParents(certificate
, issuers
); 
 184         callback(context
, parents
); 
 185         CFReleaseSafe(parents
); 
 189     /* Cache miss, let's issue a network request. */ 
 190     SecCAIssuerRequestRef request 
= 
 191         (SecCAIssuerRequestRef
)calloc(1, sizeof(*request
)); 
 192     request
->http
.queue 
= queue
; 
 193     request
->http
.completed 
= SecCAIssuerRequestCompleted
; 
 194     CFRetain(certificate
); 
 195     request
->certificate 
= certificate
; 
 196     request
->issuers 
= issuers
; 
 197     request
->issuerIX 
= 0; 
 198     request
->context 
= context
; 
 199     request
->callback 
= callback
; 
 201     return SecCAIssuerRequestIssue(request
);