1/* 2 * crlNetwork.cpp - Network support for crlTool 3 */ 4 5#include "crlNetwork.h" 6#include <CoreFoundation/CoreFoundation.h> 7#include <CoreServices/CoreServices.h> 8#include <security_cdsa_utils/cuEnc64.h> 9#include <stdlib.h> 10#include <Security/cssmapple.h> 11#include <LDAP/ldap.h> 12 13#define ocspdErrorLog(args...) printf(args) 14 15#pragma mark ----- LDAP fetch ----- 16 17/* 18 * LDAP attribute names, used if not present in URI. 19 */ 20#define LDAP_ATTR_CERT "cacertificate;binary" 21#define LDAP_ATTR_CRL "certificaterevocationlist;binary" 22 23/* 24 * Default LDAP options. 25 */ 26#define LDAP_REFERRAL_DEFAULT LDAP_OPT_ON 27 28static CSSM_RETURN ldapRtnToCssm( 29 int rtn) 30{ 31 switch(rtn) { 32 case LDAP_SERVER_DOWN: 33 case LDAP_TIMEOUT: 34 case LDAP_CONNECT_ERROR: 35 return CSSMERR_APPLETP_CRL_SERVER_DOWN; 36 case LDAP_PARAM_ERROR: 37 case LDAP_FILTER_ERROR: 38 return CSSMERR_APPLETP_CRL_BAD_URI; 39 default: 40 return CSSMERR_APPLETP_CRL_NOT_FOUND; 41 } 42} 43 44static CSSM_RETURN ldapFetch( 45 const CSSM_DATA &url, 46 LF_Type lfType, 47 CSSM_DATA &fetched) // mallocd and RETURNED 48{ 49 BerValue **value = NULL; 50 LDAPURLDesc *urlDesc = NULL; 51 int rtn; 52 LDAPMessage *msg = NULL; 53 LDAP *ldap = NULL; 54 LDAPMessage *entry = NULL; 55 bool mallocdString = false; 56 char *urlStr; 57 int numEntries; 58 CSSM_RETURN ourRtn = CSSM_OK; 59 /* attr input to ldap_search_s() */ 60 char *attrArray[2]; 61 char **attrArrayP = NULL; 62 63 /* don't assume URL string is NULL terminated */ 64 if(url.Data[url.Length - 1] == '\0') { 65 urlStr = (char *)url.Data; 66 } 67 else { 68 urlStr = (char *)malloc(url.Length + 1); 69 memmove(urlStr, url.Data, url.Length); 70 urlStr[url.Length] = '\0'; 71 mallocdString = true; 72 } 73 74 /* break up the URL into something usable */ 75 rtn = ldap_url_parse(urlStr, &urlDesc); 76 if(rtn) { 77 ocspdErrorLog("ldap_url_parse returned %d", rtn); 78 return CSSMERR_APPLETP_CRL_BAD_URI; 79 } 80 81 /* 82 * Determine what attr we're looking for. 83 */ 84 if((urlDesc->lud_attrs != NULL) && // attrs present in URL 85 (urlDesc->lud_attrs[0] != NULL) && // at least one attr present 86 (urlDesc->lud_attrs[1] == NULL)) { 87 /* 88 * Exactly one attr present in the caller-specified URL; 89 * assume that this is exactly what we want. 90 */ 91 attrArrayP = &urlDesc->lud_attrs[0]; 92 } 93 else { 94 /* use caller-specified attr */ 95 switch(lfType) { 96 case LT_Crl: 97 attrArray[0] = (char *)LDAP_ATTR_CRL; 98 break; 99 case LT_Cert: 100 attrArray[0] = (char *)LDAP_ATTR_CERT; 101 break; 102 default: 103 printf("***ldapFetch screwup: bogus lfType (%d)\n", 104 (int)lfType); 105 return CSSMERR_CSSM_INTERNAL_ERROR; 106 } 107 attrArray[1] = NULL; 108 attrArrayP = &attrArray[0]; 109 } 110 111 /* establish connection */ 112 rtn = ldap_initialize(&ldap, urlStr); 113 if(rtn) { 114 ocspdErrorLog("ldap_initialize returned %d\n", rtn); 115 return ldapRtnToCssm(rtn); 116 } 117 /* subsequent errors to cleanup: */ 118 rtn = ldap_simple_bind_s(ldap, NULL, NULL); 119 if(rtn) { 120 ocspdErrorLog("ldap_simple_bind_s returned %d\n", rtn); 121 ourRtn = ldapRtnToCssm(rtn); 122 goto cleanup; 123 } 124 125 rtn = ldap_set_option(ldap, LDAP_OPT_REFERRALS, LDAP_REFERRAL_DEFAULT); 126 if(rtn) { 127 ocspdErrorLog("ldap_set_option(referrals) returned %d\n", rtn); 128 ourRtn = ldapRtnToCssm(rtn); 129 goto cleanup; 130 } 131 132 rtn = ldap_search_s( 133 ldap, 134 urlDesc->lud_dn, 135 LDAP_SCOPE_SUBTREE, 136 urlDesc->lud_filter, 137 urlDesc->lud_attrs, 138 0, // attrsonly 139 &msg); 140 if(rtn) { 141 ocspdErrorLog("ldap_search_s returned %d\n", rtn); 142 ourRtn = ldapRtnToCssm(rtn); 143 goto cleanup; 144 } 145 146 /* 147 * We require exactly one entry (for now). 148 */ 149 numEntries = ldap_count_entries(ldap, msg); 150 if(numEntries != 1) { 151 ocspdErrorLog("tpCrlViaLdap: numEntries %d\n", numEntries); 152 ourRtn = CSSMERR_APPLETP_CRL_NOT_FOUND; 153 goto cleanup; 154 } 155 156 entry = ldap_first_entry(ldap, msg); 157 value = ldap_get_values_len(ldap, msg, attrArrayP[0]); 158 if(value == NULL) { 159 ocspdErrorLog("Error on ldap_get_values_len\n"); 160 ourRtn = CSSMERR_APPLETP_CRL_NOT_FOUND; 161 goto cleanup; 162 } 163 164 fetched.Length = value[0]->bv_len; 165 fetched.Data = (uint8 *)malloc(fetched.Length); 166 memmove(fetched.Data, value[0]->bv_val, fetched.Length); 167 168 ldap_value_free_len(value); 169 ourRtn = CSSM_OK; 170cleanup: 171 if(msg) { 172 ldap_msgfree(msg); 173 } 174 if(mallocdString) { 175 free(urlStr); 176 } 177 ldap_free_urldesc(urlDesc); 178 rtn = ldap_unbind(ldap); 179 if(rtn) { 180 ocspdErrorLog("Error %d on ldap_unbind\n", rtn); 181 /* oh well */ 182 } 183 return ourRtn; 184} 185 186#pragma mark ----- HTTP fetch via GET ----- 187 188/* fetch via HTTP */ 189static CSSM_RETURN httpFetch( 190 const CSSM_DATA &url, 191 CSSM_DATA &fetched) // mallocd in alloc space and RETURNED 192{ 193 /* trim off possible NULL terminator */ 194 CSSM_DATA theUrl = url; 195 if(theUrl.Data[theUrl.Length - 1] == '\0') { 196 theUrl.Length--; 197 } 198 CFURLRef cfUrl = CFURLCreateWithBytes(NULL, 199 theUrl.Data, theUrl.Length, 200 kCFStringEncodingUTF8, // right? 201 //kCFStringEncodingASCII, // right? 202 NULL); // this is absolute path 203 if(cfUrl == NULL) { 204 ocspdErrorLog("CFURLCreateWithBytes returned NULL\n"); 205 return CSSMERR_APPLETP_CRL_BAD_URI; 206 } 207 CFDataRef urlData = NULL; 208 SInt32 errorCode; 209 Boolean brtn = CFURLCreateDataAndPropertiesFromResource(NULL, 210 cfUrl, 211 &urlData, 212 NULL, // no properties 213 NULL, 214 &errorCode); 215 CFRelease(cfUrl); 216 if(!brtn) { 217 ocspdErrorLog("CFURLCreateDataAndPropertiesFromResource err: %d\n", 218 (int)errorCode); 219 if(urlData) { 220 return CSSMERR_APPLETP_NETWORK_FAILURE; 221 } 222 } 223 if(urlData == NULL) { 224 ocspdErrorLog("CFURLCreateDataAndPropertiesFromResource: no data\n"); 225 return CSSMERR_APPLETP_NETWORK_FAILURE; 226 } 227 CFIndex len = CFDataGetLength(urlData); 228 fetched.Data = (uint8 *)malloc(len); 229 fetched.Length = len; 230 memmove(fetched.Data, CFDataGetBytePtr(urlData), len); 231 CFRelease(urlData); 232 return CSSM_OK; 233} 234 235/* Fetch cert or CRL from net, we figure out the schema */ 236CSSM_RETURN crlNetFetch( 237 const CSSM_DATA *url, 238 LF_Type lfType, 239 CSSM_DATA *fetched) // mallocd in alloc space and RETURNED 240{ 241 if(url->Length < 5) { 242 return CSSMERR_APPLETP_CRL_BAD_URI; 243 } 244 if(!strncmp((char *)url->Data, "ldap:", 5)) { 245 return ldapFetch(*url, lfType, *fetched); 246 } 247 if(!strncmp((char *)url->Data, "http:", 5) || 248 !strncmp((char *)url->Data, "https:", 6)) { 249 return httpFetch(*url, *fetched); 250 } 251 return CSSMERR_APPLETP_CRL_BAD_URI; 252} 253 254